Page 1 of 1
How using .query stack in REST API?
Posted: Fri Feb 02, 2024 4:11 am
by DenSyo77
How to work with query stack in REST API?
For example, print address lists with condition:
/ip firewall address-list print where (list=a or list=b or list=c) and address=d
in REST API like this POST request /rest/ip/firewall/address-list/print
{".query": ["list=a","list=b","#|","list=c","#|","address=d","#&"]}
How to create a condition with brackets like this expression?
/ip firewall address-list print where (list=a or list=b or list=c) and (address=d or comment=d)
The documentation says that can access the query stack using indexes, but I don’t understand how it works.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 4:48 am
by Amm0
I have an example here:
viewtopic.php?t=198974#p1021503
e.g.
USER=admin ROUTER=192.168.88.1; curl -l -u $USER -X POST http://$ROUTER/rest/ip/firewall/nat/print -H "Content-Type: application/json" --data '{".query": ["chain=dstnat","chain=srcnat","#|!"]}'
It's tricky with .query in JSON. The comparison operators are all "stack based" (like an old HP RPN calculator). But AFAIK all operators should be at end of the array, working down the stack.
How .query work is semi-described in API docs as it follows Mikrotik older/non-HTTP API:
https://help.mikrotik.com/docs/display/ ... PI-Queries – but seems you figured out that part.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 5:19 am
by Amm0
I tried your version and it works for me...
and this version of .query also worked:
USER=admin ROUTER=192.168.88.1; curl -l -u $USER -X POST http://$ROUTER/rest/ip/firewall/address-list/print -H "Content-Type: application/json" --data '{".query": ["list=a","list=b","list=c","#|","#|","address=159.148.147.252","#&"]}' -- | jq '.'
[
{
".id": "*A1E70",
"address": "159.148.147.252",
"comment": "ftp.mikrotik.com",
"creation-time": "2024-02-01 19:11:41",
"disabled": "false",
"dynamic": "true",
"list": "a"
},
{
".id": "*A1E71",
"address": "159.148.147.252",
"comment": "ftp.mikrotik.com",
"creation-time": "2024-02-01 19:11:51",
"disabled": "false",
"dynamic": "true",
"list": "b"
},
{
".id": "*A1E72",
"address": "159.148.147.252",
"comment": "ftp.mikrotik.com",
"creation-time": "2024-02-01 19:12:12",
"disabled": "false",
"dynamic": "true",
"list": "c"
}
]
using this test data:
/ip firewall address-list
add address=ftp.mikrotik.com list=a
add address=ftp.mikrotik.com list=b
add address=ftp.mikrotik.com list=c
add address=cloud.mikrotik.com list=c
add address=cloud2.mikrotik.com list=c
add address=ftp.mikrotik.com list=e
with ftp.mikrotik.com resolve to 159.148.147.252
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 5:30 am
by DenSyo77
This query expression: {".query": ["list=a","list=b","#|","list=c","#|","address=d","#&"]} is works, yes, and I using your example for write this.
I'm interested in how to construct an expression similar to this: where (list=a or list=b or list=c) and (address=d or comment=d)
The documentation talks about indexes of expressions sent to the stack, and if try to use constructs like: "#0|3" or "#0&4", can see that this has an impact on the query result, but there is absolutely no understanding of how to use it correctly.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 5:52 am
by Amm0
LOL. I read what you wrote but cut-and-pasted the wrong one.
I think this should work:
["list=a","list=b","list=c","#|","#|","address=159.148.147.252","comment=rem", "#|", "#&"]
adding this to above...
/ip/firewall/address-list/add address=
www.mikrotik.com comment=rem list=a
"#....." op resolves two items in the stack into one, BUT the one result remains on the stack... e.g. removes the two item, but pushes true/false to stack.
Maybe if you visual like this since when the #| or #& operators resolves...
["list=a","list=b","list=c","#|","#|","address=159.148.147.252","comment=rem", "#|", "#&"]
["list=a",true,"#|","address=159.148.147.252","comment=rem", "#|", "#&"]
[true,"address=159.148.147.252","comment=rem", "#|", "#&"]
[true,true, "#&"]
[true]
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 5:53 am
by DenSyo77
Yes! I'm still testing it, but it's already working:
{".query": ["list=a","list=b","#|","list=c","#|","comment=d","address=d","#|","#&"]}
equal to: (list=a or list=b or list=c) and (address=d or comment=d)
The great force of brute force is at work, but trying to use the numbers was unnecessary...
Thanks, Amm0! 10 minutes passed and the stack processing logic finally became clear to me
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 6:03 am
by Amm0
I did use an HP calculator for years.
I kinda use "jq" in shell scripts or map()/reduce() in JavaScript to avoid dealing with the .query – although it more efficient to use .query to avoid unneeded data transfer.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 6:08 am
by Amm0
FWIW, I'm pretty sure the last "#&" is unnecessary since default is AND. And in the example above, the stack have [true, true] on a match.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 6:13 am
by DenSyo77
Yes, works without last and
{".query": ["list=a","list=b","#|","list=c","#|","comment=d","address=d","#|"]}
{".query": ["list=a","list=b","list=c","#|","#|","comment=d","address=d","#|"]}
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 7:07 am
by DenSyo77
Since already dealt with the query, did it as needed.
{".query": ["disabled=false","list=a","list=b","#|","list=c","#|","comment=d","address=d","#|","timeout","#!","dynamic=true","#&!"]}
is equal to: where !disabled and (list=a or list=b or list=c) and (address=d or comment=d) and !(!timeout and dynamic)
- thus, dynamic addresses created by the system based on domain names are ignored.
Will make an explanation to make it easier for everyone interested to understand. And is applied by default to all expression results not explicit used on operation in stack:
{".query": ["disabled=false" AND "list=a","list=b","#|","list=c","#|" AND "comment=d","address=d","#|" AND "timeout","#!","dynamic=true","#&!"]}
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 2:41 pm
by DenSyo77
Indexes can be used in an expression, but the logic is not always clear and there are no advantages over a regular chain, except perhaps to do obfuscation.
{".query": ["disabled=true","list=a","list=b","list=c","#|","#|","comment=d","address=d","#|","timeout","#!","dynamic=true","#&!","#2&1&0"]}
- in this example the expression "disabled=true" is ignored, "timeout","#!" - timeout is nothing, "#2&1&0" - changing the index order gives a different result, it looks like this is the "left to right" that documentation says.
Re: How using .query stack in REST API?
Posted: Fri Feb 02, 2024 4:14 pm
by Amm0
, except perhaps to do obfuscation.
{".query": [...,"#&!","#2&1&0"]}
Well...there we're no example of using the "stack index" operators AKAIK. Bravo!
Do think "#|" and "#&" – in right spots – is likely what most folks need to know about .query in REST*. And even those two ops, with the stack, is pretty far from a "print where". e.g. if you're trying to "port" a CLI into a REST request.
* And perhaps using =true or =false for boolean config items like disable= etc — which you show here too.
Re: How using .query stack in REST API?
Posted: Sat Feb 03, 2024 1:25 am
by DenSyo77
Amm0, title of the post has taken on a different meaning, now this is an expanded version of your previous instructions.
Block that uses indexes pushes the result to the top of stack, clearing the entire stack - all expressions unused before this step will be lost. Operations & and | can be applied to indexes, but it is difficult to understand the priority and logic of the actions performed. The only thing that is clear is that if something goes wrong, the expression is written with an error, then the system will return either all addresses from the firewall lists (accessing a non-existent index), or result of the last index in expression (syntax or procedure error).
"#." creates a copy of the top of stack - this is an interesting feature that can be used to construct complex expressions.
For some reason, I have never encountered such an approach with a stack to organizing logical calculations before. Really liked its simplicity of implementation, will use it in my projects when need to be able to set the behavior of an object by user in settings.
Re: How using .query stack in REST API?
Posted: Sat Feb 03, 2024 4:23 am
by Amm0
For some reason, I have never encountered such an approach with a stack to organizing logical calculations before. Really liked its simplicity of implementation, will use it in my projects when need to be able to set the behavior of an object by user in settings.
I like esoteric programming languages. RouterOS script is in that category. Someone at Mikrotik must have read Ken Iverson books (creator of array languages like APL, J) & be an expert at lex/yacc is all I know. But if you like ".query stack", you'd like
https://www.uiua.org - dozen of primitives to operate on a stack expressed as unicode symbols.
Re: How using .query stack in REST API?
Posted: Sat Feb 03, 2024 4:52 am
by DenSyo77
Thank you very much, Amm0! Very interesting ideas that may be useful to me.