Hi,
I already created a script, works fine if I run the script from WinBox.
Now I’m trying to run the script via REST API (https-url). www-ssl (with certificate), api, api-ssl activated, firewall rule created.
https://remote:xxx192.168.1.88/rest/system/script/run/myscript => doesn’t work, response: {“detail”:“no such command prefix”,“error”:400,“message”:“Bad Request”}
What’s wrong with my syntax?
It shouldn’t work like that… but some stuff does vary by command. It might just map both “.id” to “numbers=”* as the “$1”/unnamed argument to /system/script/run and let that command sort it out. (* “numbers” is .id’s cousin, and weird too, sometimes it can be a name not number too). Now, I’d avoid using name in .id, since that’s not consistent with some/most calls. And seems a bug fix away from not working in future.
If you’re using curl, few options to a “lookup by name”:
If familiar with jq, it’s likely better to a GET to find all ids, pipe that to jq to filter the one you want, and pipe again to a 2nd curl with the id
There is the .query syntax offered by REST API on a POST ending in /print. It’s still two REST calls, one to find .id by name (adding .query “stack” to JSON in 1st POST), the 2nd to /system/script/run. This thread has some example of using .query: http://forum.mikrotik.com/t/how-using-query-stack-in-rest-api/173298/1 & links to others with more .query examples
Lookup the .id on RouterOS using “/system/script/print show-id”. That won’t change unless you delete the script. One call and easy.
All “APIs” in RouterOS really go down some fixed schema. And the CLI has a tool /console/inspect that allow you kinda see the scheme, which AFAIK guides what REST accepts. FWIW, if you want do a lot with REST API, I publish the “schema” that’s usable in tools like Postman here: https://tikoci.github.io/restraml with a discussion of how to use it with Postman and VSCode here: http://forum.mikrotik.com/t/rest-api-schema-for-postman-more/169502/1
So /console/inspect does tell you want numbers is defined to & for script/run it seems to include names. If you want to get into the weeds, you can kinda see what might be going on – still kinda odd REST takes name as .id however:
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE NESTED NONORM TEXT
syntax collection 0 yes
syntax explanation 1 no Item number
syntax use-script-permissions explanation 1 no
Columns: TYPE, SYMBOL, SYMBOL-TYPE, NESTED, NONORM, TEXT
TYPE SYMBOL SYMBOL-TYPE NESTED NONORM TEXT
syntax ItemName definition 0 no
syntax definition 1 no _YAML | rancher | > lsbridge > | > PIANO > | …
So looks to be .id or name,… So maybe REST API must map .id to the generic if there is not an “.id”?
But leave it @jaclaz to actually try using .id with a name. Since REST API does just map into the native API, and from API it also takes a name from /system/script in a quick test. From a pure API design POV, it really should fail if you explicitly use .id IMO.
The net is “number” will take a name, which might be better than .id… — which is strange sounding, but “number” is in the schema it seems. In RouterOS [7.16+] fetch syntax (to itself), that works:
Nothing on the REST API. Mikrotik also has a low-level protocol called just “API”.
FWIW, they have not changed either REST API or API protocol in years (commands used do change, not the protocol itself). So that’s not a regular thing. And like I said, I don’t see any effect in REST API from the change in low-level API.
In fact, if I had to guess, they might have added !empty to improve REST API performance in some cases (since REST API likely just “wraps” the low-level based on debug logs). But I actually don’t know why !empty become a thing. But it really should not affect REST API.
To assuage fears… the “restraml” schema site above, runs 50K REST API to generate the data. So if something wholesale was broken in REST, that almost certainly catch it. But it 99% runs without issue on each build Mikrotik releases. And time it hasn’t, it wasn’t REST API at issue.
Basically “number” is the “syntactic sugar”, so in /bin/sh terms, essentially, it gets mapped to the $1 in a CLI command. Since “run” takes a name as $1, the APIs following same. Or at least that’s what I’ve seen. It’s the “.id” part that’s weird here. “number” should work POST request that show it in schema or /console/inspect - but it will follow how that particular command treats the generic “number” (which again can be name or .id, or at CLI, “print #”)
Only for the record, jaclaz has no idea about “why” it works , my logic has only been that it didn’t seem possible to me that the only way to reference a script would have been enumerating it with print as such mechanism would have been too prone to possible errors (think of a complex environment where scripts are locally created and deleted by scheduler or whatever) and some other way had to exist, and looked around to find how other people used the API to run a script.
rextended has more or less consumed his keyboard typing how you should never use numbers to make reference to anything in ROS, and it is very good advice, it seemed to me impossible that it was the only way in this case.
Now, why it is seemingly not well (or at all) documented is the real mistery to me.
When you leave the standard [get] [set] [print] [remove] operators in POST (or at CLI too), some of the “rules” are broken. For example, “run” is not a standard command, it’s specialized to /system/script - kinda like a function. While things from get/set/remove are attributes (/properties), more strictly follow rules. Command like “run” are freed from such shackles, and can take what they want.
Basically a REST POST will follow the CLI. And “run” takes a name, so same can be done with REST. That part isn’t weird. I just would have expected it needing to be in { “number”: “myscript” } — I generally trust /console/inspect at being definitive to what JSON is needed REST POST. But it doesn’t mean more isn’t mapped…
But another way to look at it… is .id is just a specific form of schema’s , so .id get mapped into that. And in case of “run”, a can be name, but REST API is merely providing some value to run, which REST mapped to value of {“.id”: …}