[API suggestion] Type indicator word
RouterOS Scripting and API

6 posts   •   Page 1 of 1
User avatar
boen_robot
Forum Guru
Forum Guru
 
Posts: 1317
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

[API suggestion] Type indicator word

by boen_robot » Tue Sep 06, 2011 10:53 pm

First stop, sorry if this is not the way to actually make feature requests. I'd resend this to the appropriate place if I must. I simply don't see another way to do so (beyond the support email...).

It would be nice if the API could in some fashion return type information for the current reply. This would make creation of type aware clients easier, which would in turn make work with such clients easier.

Right now, clients need to either read everything as a string, or embed in themselves "knowledge" about the types of the arguments in each section. Having that knowledge would force them to keep up with RouterOS though, which would make clients fragile (or would limit MikroTik in their work due to desire to keep clients compatible... both scenarios are bad for the end user).

I propose a new API word that would carry type information. The exact format of the word is irrelevant, although I do have one in mind, specified below.

For example, let's say we do
Code: Select all
/queue/simple/print
=.proplist=.id,name,disabled,dst-address,target-addresses,priority

Each reply is currently something like
Code: Select all
!re
=.id=*1
=name=queue1
=disabled=no
=dst-address=192.168.10.1
=target-addresses=192.168.0.100,192.168.0.1
=priority=8

With the proposed word, it would look something like:
Code: Select all
!re
=.id=*1
=name=queue1
=disabled=no
=dst-address=192.168.10.1
=target-addresses=192.168.0.100,192.168.0.1
=priority=8
.argumentTypes .id=ID name=string disabled=boolean dst-address=IP target-addresses=array[IP] priority=number


The API word is called "argumentTypes", and after it there is a space separated list of name=value pairs. The name of the property, and its scripting type as the value. Note that in the case of arrays, if RouterOS knows the types within the array, it shoud fill them too (in this case surrounded with "[]").
PEAR2_Net_RouterOS(1.0.0b5) - My API client in PHP
(Karma? If you want... no pressure...)

User avatar
janisk
MikroTik Support
MikroTik Support
 
Posts: 5925
Joined: Tue Feb 14, 2006 10:46 am
Location: Riga, Latvia

Re: [API suggestion] Type indicator word

by janisk » Wed Sep 07, 2011 10:41 am

IMHO not sure this is would solve anything. There are complex data types in a lot of places that would require serious parsing to get what this is exactly, simple example - field that accepts ipv4 or ipv6 addresses, field that accepts regexp or text. So, parsing stuff you receive or parsing data type return, i see no big difference.

edit: also, API handles types internally, so you can write something and if it is wrong you will get the trap. Just handle these traps gracefully.

User avatar
boen_robot
Forum Guru
Forum Guru
 
Posts: 1317
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: [API suggestion] Type indicator word

by boen_robot » Wed Sep 07, 2011 1:59 pm

janisk wrote:IMHO not sure this is would solve anything. There are complex data types in a lot of places that would require serious parsing to get what this is exactly, simple example - field that accepts ipv4 or ipv6 addresses

Aren't both of those treated as of datatype "IP" in scripting?

janisk wrote:field that accepts regexp or text

Is regexp even a datatype in scripting? It's surely not a documented one.

janisk wrote:API handles types internally, so you can write something and if it is wrong you will get the trap. Just handle these traps gracefully.

In terms of requests, that's right. But I'm talking in terms of responses. The client has no idea what datatype a certain property in a response is supposed to be, which in turn forces the presentation of all properties as strings OR forces the client to guess the type in some fashion (which would inevitably lead to false positives and false negatives of guesses).

Consider the part of the example:
Code: Select all
=disabled=no

Is this a boolean property with a value of false, or is it a string property with a value of "no"? The client could implement a rule that says "any time the property 'disabled' is found, it is assumed to be a boolean". This would be correct assumption for current versions. Suppose that in a future version, it is decided that a certain special "disable" property would instead be a string detailing disabling conditions in a certain format, e.g.
Code: Select all
=disabled=1m10s

("disabled for the next 1 minute and 10 seconds")

Now, because all other "disabled" properties are still booleans, the client needs to add the knowledge that this particular instance of "disabled" is not a boolean. Until it does so, the behaviour of this field would be unpredictable, or depending on the client's implementation, cause a crash even.
PEAR2_Net_RouterOS(1.0.0b5) - My API client in PHP
(Karma? If you want... no pressure...)

User avatar
janisk
MikroTik Support
MikroTik Support
 
Posts: 5925
Joined: Tue Feb 14, 2006 10:46 am
Location: Riga, Latvia

Re: [API suggestion] Type indicator word

by janisk » Wed Sep 07, 2011 2:58 pm

scripting is whole different matter. There is nothing of scripting in API. While one has some types API deals with internal data types of fields.

As an example of something really complex -
Code: Select all
/ping
=address=<something>


that something can be IPv6 address, IPv4 address, MAC address or a host name for good measure, and lets do not forget that it can be IPv6 link-local address that has to have %interface as postfix.

and class (from oop paradigm) for every menu sounds like madness.

it sounds useful as a whole, but i think it is not the way it has to be implemented.

still it is IMHO and to bring some other perspective into the conversation.

What you can look at - is user manual, where every single field should be defined on what it holds. If field is not well described point to it and we will describe it properly.

User avatar
boen_robot
Forum Guru
Forum Guru
 
Posts: 1317
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: [API suggestion] Type indicator word

by boen_robot » Wed Sep 07, 2011 3:44 pm

This example is also in terms of requests, not responses. In terms of responses, whatever <something> is, you still get data replies with the same properties. Even if those data types differ between different data replies, the fact that each data reply carries its own type information will keep it reliable.

I realize that the API currently has nothing to do with scripting. That's sort of the point of the suggestion (the "new" thing) - adding the type information to responses, with the "types" being those that are defined in scripting (so there's no need to worry about incompatabilities with a 3rd party type set).

It's not about the types in responses being documented or not... it's about them being realiably detectable, rather than documented, so that they're being automatically casted properly.
PEAR2_Net_RouterOS(1.0.0b5) - My API client in PHP
(Karma? If you want... no pressure...)

User avatar
boen_robot
Forum Guru
Forum Guru
 
Posts: 1317
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: [API suggestion] Type indicator word

by boen_robot » Thu Sep 08, 2011 9:57 pm

Here's a more explicit example, with some screenshots to illustrate the benefits.

I'll use my PHP client...

Say I have an HTML table with form fields for everything that's currently in a section (I'll use the /queue/simple section, limited for brevity).

Right now, I can create forms that accept and are prefilled with text, like so:
Code: Select all
<?php
namespace PEAR2
\Net\RouterOS;

require_once 'PEAR2/Net/RouterOS/autoload.php';
header('Content-Type: text/html;charset=UTF-8');
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <title>TEST</title>
    </head>
    <body>
        <form action="formProcessor.php" method="post">
            <?php
            $client 
= new Client('192.168.0.1', 'apifull', 'apifull');

            $request = new Request('/queue/simple/print');
            $request->setArgument('.proplist',
                '.id,name,disabled,dst-address,target-addresses,priority'
            );
            echo '<table>';
            foreach ($client->sendSync($request) as $index => $response) {
                echo '<tr>';
                foreach ($response->getAllArguments() as $name => $value) {
                    echo '<td>';
                    echo '<input type="hidden" name="oldValues[',$index,'][', $name, ']" value="',
                        $value, '"/>';
                        
                    echo 
'<input name="data[', $index, '][', $name, ']" ';
                    echo 'type="text" value="', $value, '" />';
                    
                    echo 
'</td>';
                }
                echo '</tr>';
            }
            echo '</table>';
            ?>
            <input type="submit" value="Submit changes" />
        </form>
    </body>
</html>

It would be rendered something like
typeless.png
typeless.png (6.37 KiB) Viewed 1288 times

This works. So far, so good. It's not really a problem to leave it like that. As you said, if the user enters a wrong text value, there will be a !trap response. But it would be nice if I could instead render the form more like:

typed.png
typed.png (5.48 KiB) Viewed 1288 times


I could do this by explicitly enumerating all instances where I'm aware that a property is a boolean or ID, such as "disabled" and ".id". I could do this either within the client (the Response object) or outside of it, like so:
Code: Select all
 <?php
namespace PEAR2
\Net\RouterOS;

require_once 'PEAR2/Net/RouterOS/autoload.php';
header('Content-Type: text/html;charset=UTF-8');
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <title>TEST</title>
    </head>
    <body>
        <form action="formProcessor.php" method="post">
            <?php
            $client 
= new Client('192.168.0.1', 'apifull', 'apifull');

            $request = new Request('/queue/simple/print');
            $request->setArgument('.proplist',
                '.id,name,disabled,dst-address,target-addresses,priority'
            );
            echo '<table>';
            foreach ($client->sendSync($request) as $index => $response) {
                echo '<tr>';
                foreach ($response->getAllArguments() as $name => $value) {
                    if ($name === '.id') {
                        $value = hexdec(substr($value, 1));
                        echo '<input type="hidden" name="toID[', $index,
                        ']" value="', $name, '" />';
                    }
                    echo '<td>';
                    echo '<input type="hidden" name="oldValues[',
                        $index, '][', $name,
                        ']" value="', $value, '" />';

                    echo '<input name="data[', $index, '][', $name, ']" ';
                    if ($name === 'disabled') {
                        echo 'type="checkbox"';
                        if ($value === 'true') {
                            echo ' checked="checked"';
                        }
                    } else {
                        echo 'type="text" value="', $value, '"';
                    }
                    echo ' />';
                    echo '</td>';
                }
                echo '</tr>';
            }
            echo '</table>';
            ?>
            <input type="submit" value="Submit changes" />
        </form>
    </body>
</html>

This too works... but it works for the time being only, and only for properties I'm aware to be of said type. It's an extremely fragile and brute force way of creating a UI that is more intuitive than plain text boxes. But there's no way for it to be otherwise without RouterOS sharing some type information. If it did, the above could be written something more like this (assuming I also rework the client to honor the type information, allow the user to choose to cast based on it, and get the type as given by that word):
Code: Select all
<?php
namespace PEAR2
\Net\RouterOS;

require_once 'PEAR2/Net/RouterOS/autoload.php';
header('Content-Type: text/html;charset=UTF-8');
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
        <title>TEST</title>
    </head>
    <body>
        <form action="formProcessor.php" method="post">
            <?php
            $client 
= new Client('192.168.0.1', 'apifull', 'apifull');

            $request = new Request('/queue/simple/print');
            $request->setArgument('.proplist',
                '.id,name,disabled,dst-address,target-addresses,priority'
            );
            echo '<table>';
            foreach ($client->sendSync($request) as $index => $response) {
                echo '<tr>';
                foreach ($response->getAllArguments() as $name => $value) {
                    echo '<td>';
                    echo '<input type="hidden" name="oldValues[',
                        $index, '][', $name,
                        ']" value="', $value, '" />';
                    echo '<input type="hidden" name="types[',
                        $index, '][', $name,
                        ']" value="', $response->getArgumentType($name), '" />';

                    echo '<input name="data[', $index, '][', $name, ']" ';

                    switch (gettype($value)) {
                        case 'bool':
                            echo 'type="checkbox"';
                            if ($value) {
                                echo ' checked="checked"';
                            }
                            break;
                        case 'int':
                        case 'double':
                            /* Let's say for example that later we'd do JS
                              validation and/or add a numeric keypad for numbers,
                              and this class here is just the anchor.
                             */
                            echo 'class="number" ';
                        default:
                            echo 'type="text" value="', $value, '"';
                    }
                    echo ' />';
                    echo '</td>';
                }
                echo '</tr>';
            }
            echo '</table>';
            ?>
            <input type="submit" value="Submit changes" />
        </form>
    </body>
</html>


Not only does this last code work... it would work for any response. For example, I could switch to /ip/firewall/nat, and get a checkbox for "fragment" even though I never listed it.
PEAR2_Net_RouterOS(1.0.0b5) - My API client in PHP
(Karma? If you want... no pressure...)

6 posts   •   Page 1 of 1

Who is online

Users browsing this forum: No registered users and 10 guests

It is currently Sat Dec 20, 2014 8:11 am