Community discussions

MikroTik App
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Can't Query Graphql site

Wed Apr 17, 2024 10:57 pm

I am trying to use the /fetch tool to query some data via graphql. However no matter what I have tried, I get a Syntax Error. As far as I can see, the query is correct as it works in CURL and postman .

Here is the query. I have confirmed the URL and the bearer token are correct. I have onbiously changed the URL and the token for security purposes but have not changed the http-data . It is just the query that I am running and I am assuming there is an escape character somewhere but I can't figure out where this is.
:put ([/tool fetch url="https://somewebsite/api/graphql" \
  http-method=post \
  http-header-field="Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNjdhYjYxOWZiMGFmODZiNDMyNTcyOTI1ODcwZGRkZTI1NTJlMGVlNzdkNjM2ZDQxNGQxYjlmOGI3NDNhNWE1MjM3MGYwZWFkNGVkN2NlNTgiLCJpYXQiOjE3MTMzNzU4MTQuMzcxNiwibmJmIjoxNzEzMzc1ODE0LjM3MTYsImV4cCI6MjE0NTkxNjgwMC4xMDM3LCJzdWIiOiIxNyIsInNjb3BlcyI6W119.XjbbSMlBYyioE4f2OLse6v5gDtfZS8SwL2hkI3tXSKZEokfZ-kbv5z4t-0901zY0ckNyXxjvPWRvnaSPTkfQSDEwoCykXE8R6S9oRb8LzZCxb1EsmGaM2wdpPwKHqqYiBsBD491rzgcWOYPAnOwx5oC7iOAKesrNsBGfRgGe1yOeN6AuzuZdF7ZicbD50y2XC4NTI69jfYKIQoFh0c1m4mcNWDynSeY6qWavi7RKoN2gzmNV8OniMIDWzOykh7_HuibosXuJ_l8MHhDQ9Py_85aWhJnZpFwCYhp2--WqMq8mZcX8QR7u54_fd20QsAQZX_DmLggeSSi_gFVhgjKnI1Hf_JcNMSpJyYpavyux4himsLtegHzcc9xlBTimvYJ0KTrBPi8i9xGe6ShdTwMHyrB68UC050dOqSm-OxxkzgLMcu2DD1PlLwoA707wIfZNT_usYrNM5ehDNqKwrUMDJ_fueqI9BwSgeuyP07QBmebj6Z99wbIkkASraxjRHDRb1YAkdNZDTNtBIsbWBKJHPXpqmQQxKF44bCux-yjGQlmY5R270H-Ru8-YbD2DQv8hj08ArqiUB2-QVx-spMoa9uoV3OhXhHor7Ot558l0J9m3ZP7cTZVlXGUjK2Dwfl5XNg1U2Kvyrgoq57vSTA8wW55kj3dCUD4fq1eIDQgLATI" \
  http-data="{\"query\":\"query accountid {accounts(id:2){entities{name}}}\"}" output=user as-value]->"data")



And here is what the terminal reports.
{"{\"query\":\"query_accountid_{accounts(id:2){entities{name}}}\"}":{"errors":[{"message":"Syntax Error: Unexpected <EOF>"}]}}
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Wed Apr 17, 2024 11:10 pm

I believe you need spaces between attributes and brackets in graphql. Might want to try something like this:
 http-data="{\"query\":\"query accountid { accounts(id:2) { entities { name }}}\"}" 
or since query is already in the JSON perhaps
 http-data="{\"query\":\"accountid { accounts(id:2) { entities { name }}}\"}" 
(this would depending the backend processing the GraphQL.

otherwise I think your escaping looking right.
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Thu Apr 18, 2024 3:02 pm

Hmm unfortunately the same response. It is so weird that it works with Curl or Postman but not with the fetch tool.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Thu Apr 18, 2024 3:14 pm

Hmm unfortunately the same response. It is so weird that it works with Curl or Postman but not with the fetch tool.
Can you post the command you're using with `curl` that works?

You may also need to add JSON as the content-type to /tool/fetch, since my guess is curl is using a --json (which sets the content type):

http-header-field="Content-Type:application/json,Authorization:Bearer eyJ0eXAiOiJKV...7cTZVlXGUjK2Dwfl5XNg1U2" \
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Thu Apr 18, 2024 3:22 pm

Sure. Tried it again in Ubuntu 22.04 with Curl and it works. I changed the website but if you actually need to do a real test, let me know and I can get you a real website to test on
curl -L -X POST 'https://somewebsite/api/graphql' -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiZDdmYTYzN2UxY2FjZmQ4ZDkwNjFkZDY2MDhiYzBiZTk2NTY5ZmUyMTZkYjkxZWZiNjVhM2NhNzVkMmUxZGZkZDQyMzc4OTFmNTA3Mzg1YTUiLCJpYXQiOjE3MTIyNDE1MzUuMDE0NSwibmJmIjoxNzEyMjQxNTM1LjAxNDUsImV4cCI6MjE0NTkxNjgwMC44NTQyLCJzdWIiOiIzIiwic2NvcGVzIjpbXX0.CfrAkrsbw-161SCO4QpFuzW8k4ygkPPWUzr709gSvRFACZjzggHw4yO3SB1en9TXepu6GPrBzDUvsKrcSPNmaZGdS2wLe8pvcZygCGRatU6itVQ12CxDIhG7E5H9bmSeKc7okL7pSHW0j4huEXxijABcoCZ6tIIfKUBwFsLak7OSHQphQLc431TphsCFyE8kfDbJ-50u3MRJCYl1fGA-n7ztM5oMpZxtE_t8O0Gd0ON0tUM_8sYPHexM_w9pYTlunN_cEoeWDTmXl5jMZMQZU38CvHXHis_RUIn2cMtNvAA0mSaVs_LaBBWfQJVCW_zZY5Acf2beIl2faniZQ7RNkyCflLhjVipS-qHCX1AteRkplow9Sh0xBmPC1zqy3ECpl56qifxqX79T_T84bx0NliBRn3UfNYROHHnOjpAfLvbDuO31WmKQk_r8cWarHG32_831RSdV2BjIsYQudZ9xRwx6r_guq2Y5kARYsEkJJuv3COJvDOOD8E5r1Zg8NWKJcgv7WBN80gOPUqJqN6bqIymxoXkvEP9AY0-GHZy_s89oOKj0cwn3M2hz7JERHtUgVn9z1bLnelzJbvYmjxaWo4Hzwia91IsqAWkGpz4_lnrmR6hxQiRtLLdCyCX7yj9AOygcWS15xB6cfwzaqn0m-RcQHyH7eSLAaz7_Z-d37j0' -H 'Content-Type: application/json' --data-raw '{"query":"query accountid {accounts(id:2){entities{name}}}"}'
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Thu Apr 18, 2024 3:25 pm

Well, it the -H 'Content-Type: application/json' that's messing in your /tool/fetch - that's setting it as JSON.
:put ([/tool fetch url="https://somewebsite/api/graphql" \
  http-method=post \
  http-header-field="Content-Type:application/json,Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiNjdhYjYxOWZiMGFmODZiNDMyNTcyOTI1ODcwZGRkZTI1NTJlMGVlNzdkNjM2ZDQxNGQxYjlmOGI3NDNhNWE1MjM3MGYwZWFkNGVkN2NlNTgiLCJpYXQiOjE3MTMzNzU4MTQuMzcxNiwibmJmIjoxNzEzMzc1ODE0LjM3MTYsImV4cCI6MjE0NTkxNjgwMC4xMDM3LCJzdWIiOiIxNyIsInNjb3BlcyI6W119.XjbbSMlBYyioE4f2OLse6v5gDtfZS8SwL2hkI3tXSKZEokfZ-kbv5z4t-0901zY0ckNyXxjvPWRvnaSPTkfQSDEwoCykXE8R6S9oRb8LzZCxb1EsmGaM2wdpPwKHqqYiBsBD491rzgcWOYPAnOwx5oC7iOAKesrNsBGfRgGe1yOeN6AuzuZdF7ZicbD50y2XC4NTI69jfYKIQoFh0c1m4mcNWDynSeY6qWavi7RKoN2gzmNV8OniMIDWzOykh7_HuibosXuJ_l8MHhDQ9Py_85aWhJnZpFwCYhp2--WqMq8mZcX8QR7u54_fd20QsAQZX_DmLggeSSi_gFVhgjKnI1Hf_JcNMSpJyYpavyux4himsLtegHzcc9xlBTimvYJ0KTrBPi8i9xGe6ShdTwMHyrB68UC050dOqSm-OxxkzgLMcu2DD1PlLwoA707wIfZNT_usYrNM5ehDNqKwrUMDJ_fueqI9BwSgeuyP07QBmebj6Z99wbIkkASraxjRHDRb1YAkdNZDTNtBIsbWBKJHPXpqmQQxKF44bCux-yjGQlmY5R270H-Ru8-YbD2DQv8hj08ArqiUB2-QVx-spMoa9uoV3OhXhHor7Ot558l0J9m3ZP7cTZVlXGUjK2Dwfl5XNg1U2Kvyrgoq57vSTA8wW55kj3dCUD4fq1eIDQgLATI" \
  http-data="{\"query\":\"query accountid {accounts(id:2){entities{name}}}\"}" output=user as-value]->"data")
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Thu Apr 18, 2024 3:38 pm

Unfortunately this was something I thought as well before I opened up this post. Tried with Content-Type added in the http-header-field and still got the same Unexpected EOF error.
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Thu Apr 18, 2024 10:27 pm

So I did some more digging around. Since I could not see what the instance was seeing in my query , I started to send the body to webhook.site. From looking at it, there are no escape characters or anything like this and it seems like Mikrotik is sending everything correctly.
Then I started to playaround with Githubs graphql API. I formatted it the same as the above script and it worked on Github.
So the issue seems to be with how this website interacts with what is being sent in Mikrotik??

Is there a way to run a curl command on Mikrotik?
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1111
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: Can't Query Graphql site

Thu Apr 18, 2024 11:34 pm

Possibly in a slim container, if the hardware allows, but it feels a bit overkill. I mean, it should be possible to get 'fetch' to work, but how to locate the root cause of the error is probably the $100,000 question. Have you checked it's not an SSL certificate issue on either side?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Fri Apr 19, 2024 12:36 am

The quoting all looks right, and CURL is doing same "single line" GraphQL.

My other thought is /tool/fetch is using \r\n as the line ending, not just \n...
Perhaps just add \n to the end, since it's complaining about

In latest V7, there is the newer [:tolf] to convert any CRLF. So perhaps this might work:
http-data=[:tolf input="{\"query\":\"query accountid {accounts(id:2){entities{name}}}\"}"]

I'm pretty sure it's getting to GraphQL (e.g. error does look like it from HTTP server), so not sure certs or anything – that error looks like it's from GraphQL server. What GraphQL backend are you using?
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Fri Apr 19, 2024 3:17 pm

Well. Thanks to both of you for the help. I was able to just get it work with the regular tool. Here is what finally worked.
http-data="{\"query\":\"query accountid{accounts(id:2){entities{name}}}\"}" output=user as-value]->"data")

Now I need to learn more scripting so I can save the object to a variable and select the first entity returned. Hopefully I won't have to create another thread for it.

Thanks again
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Fri Apr 19, 2024 4:37 pm

To store as a variable, you can just replace the ":put " with a ":global results " would work. There are also :local variables e.g.
{
:local results ([...]->"data")
:put $results
}

The result is going to be JSON, so to get that into a RouterOS array, you need to use ":deserialize" on those results. I can't test this but something like this might be a good example:
{
# variables for fetch
:local gqlurl "https://somewebsite/api/graphql"
:local query "{\"query\":\"query accountid{accounts(id:2){entities{name}}}\"}"
:local contenttype "application/json"
:local bearer "eyJ0e...LATI"
:local headers "Content-Type: $contenttype,Authorization: Bearer $bearer"

# use variables to make fetch call and store into new "fetched" variable
:local fetched [/tool fetch url=$gqlurl http-method=post http-header-field=$headers http-data=$query output=user as-value]
:put $fetched

# could check results here, skipping for example...

# store the resulted data which is JSON in a string type
:local json ($fetched->"data")
:put $json

# convert JSON string to RouterOS array
:local results [:deserialize $json from=json]
:put $results

# results should be an array key-value map, so should be able to use RouterOS array accessors against the GraphQL query results 
:put ($results->"accountid")
}

 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Fri Apr 19, 2024 4:46 pm

A more complex example of using fetch with variables (and wrapping it in a function to make it easier to use from CLI) is one I wrote for extracting ZeroTier members via ZT's HTTP API to add static DNS entries for them:
viewtopic.php?t=204990&hilit=zerotier
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Mon May 06, 2024 9:40 pm

Thanks for your help so far.
So doing more testing and the following information is returned.
Lets say I get the following result from the graphql endpoint
{"data":{"inventory_model_field_data":{"entities":[{"id":"833"}]}}}
after de sanitizing it, I get this
data=inventory_model_field_data=entities=id=833.
However I want to convert this to array so I can grab the ID, however no matter what I do, I can't seem to be able to grab the ID.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Mon May 06, 2024 11:35 pm

Yeah that's how it RouterOS output's an array, but the array "->" operator can be used. In routeros there an "index" using numbers (e.g. JSON backets [ ]), or if "map" with key-values, then quoted named is used with the "->" routeros array accessor operator...

So if you start with your GQL as a string that converted using [:deserialize]:
# string here, but results from ([/tool/fetch ...]->"data") as "myjson" variable...
 :global myjson "{\"data\":{\"inventory_model_field_data\":{\"entities\":[{\"id\":\"833\"}]}}}"

# in V7.13+, :deserialize get the RouterOS array from the \$myjson
:global myarray [:deserialize from=json $myjson]

# NOW... if you just print it, it does not look like an array 
:put $myarray
#data=inventory_model_field_data=entities=id=833
# i.e. This is how RouterOS compact them...  
Then to access it, it should be like this:
:put ($myarray->"data"->"inventory_model_field_data"->"entities"->0) 
# id=833

:put ($myarray->"data"->"inventory_model_field_data"->"entities"->0->"id")
# 833

# or show it's an array inside the GQL, [:len] will give us the count for it, here just 1
:put [:len ($myarray->"data"->"inventory_model_field_data"->"entities")]        
# 1
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Mon May 06, 2024 11:42 pm

Yeah that's how it RouterOS output's an array, but the array "->" operator can be used. In routeros there an "index" using numbers (e.g. JSON backets [ ]), or if "map" with key-values, then quoted named is used with the "->" routeros array accessor operator...

So if you start with your GQL as a string that converted using [:deserialize]:
# string here, but results from ([/tool/fetch ...]->"data") as "myjson" variable...
 :global myjson "{\"data\":{\"inventory_model_field_data\":{\"entities\":[{\"id\":\"833\"}]}}}"

# in V7.13+, :deserialize get the RouterOS array from the \$myjson
:global myarray [:deserialize from=json $myjson]

# NOW... if you just print it, it does not look like an array 
:put $myarray
#data=inventory_model_field_data=entities=id=833
# i.e. This is how RouterOS compact them...  
Then to access it, it should be like this:
:put ($myarray->"data"->"inventory_model_field_data"->"entities"->0) 
# id=833

:put ($myarray->"data"->"inventory_model_field_data"->"entities"->0->"id")
# 833

# or show it's an array inside the GQL, [:len] will give us the count for it, here just 1
:put [:len ($myarray->"data"->"inventory_model_field_data"->"entities")]        
# 1

Note: RouterOS's fetch command also returns a data element, so there are two "data" things, in different forms. e.g.
:global myjson ([/tool/fetch url=... as-value output=user]->"data")
and that data has the JSON as a string, so get to the data element returns in the JSON... to highlight the different, this is one-line show that:
:put ([:deserialize from=json ([/tool/fetch url=... as-value output=user]->"data")]->"data"->"inventory_model_field_data"->"entities"->0->"id")
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Tue May 07, 2024 3:29 pm

Thanks for this. I am terrible at programming but RouterOS seems a bit different than anything else I have looked at(python, JS).

Really appreciate the help.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Tue May 07, 2024 4:18 pm

Thanks for this. I am terrible at programming but RouterOS seems a bit different than anything else I have looked at(python, JS).
FWIW, the [:deserialize from=json] is new operation – before :deserialize was added your problem here be a nightmare.

But fair enough, it is different from anything else ;). But so is Cisco IOS router's TCL support, which was atrociously difficult/fragile, and harder than RouterOS script.

Most of the newer routers support Docker-like containers, so if you already have some working GraphQL code elsewhere... you might be able to run it using /container – thus avoid RouterOS scripting.
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Tue May 07, 2024 7:46 pm

Thanks for this. Yes I am a noob in the programming but it seems like there are also some bugs specifically with how Fetch tool works with grapqhl.
For example I tried to query something like this
:global url "https://web-ipv6test.sonar.rocks/api/graphql"
:global testname "testtest123"
:global contentType "application/json"
:global data"{\"query\":\"query inventory{inventory_model_field_data(general_search:$testname){entities{id}}}\"}"
:put ([/tool fetch url=$url http-method=post http-header-field="Content-Type:application/json, Authorization: $authorization" http-data=$datafile mode=https output=user as-value]->"data")

and I would get good results. However I I replaced the variable value with something like "01020304", I started to get errors. This made no sense to get graphql errors. This made no sense to me so I started to do experiment to see where it breaks. It seems like anytime you have a leading 0, this would cause an issue. If I searched for "1020304" then, I would have no problem at all.

So it seems like I must go down the docker container way as it seems to be more reliable and less confusing.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Tue May 07, 2024 8:33 pm

The leading 0 in the value of $testname?

If so, you might want to quoting $testname. (Also, as quoted above, the variable name looks wrong.)
:global datafile "{\"query\":\"query inventory{inventory_model_field_data(general_search:\"$testname\"){entities{id}}}\"}"

It might something on the GQL backend that doesn't like leading 0, or assumes you mean octal/base-8, dunno...

That same GraphQL query with leading 0 works via CLI or some other GraphQL tool?
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Tue May 07, 2024 8:58 pm

Yeah works with postman and curl and any other graphql client.

Question in regards to running a docker container? Can I use specific events to trigger the docker container to run the script. For example when a lease is bound to a MAC?
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Tue May 07, 2024 9:22 pm

It not so easy with container if it's an event like dhcp-client where this script lives. I doubt there is a bug in /tool/fetch here... but one wrong escape char in query, it ain't going to work.

If it works in Postman, with the leading 0, can you cut-and-paste Postman's HTTP and cURL "Code snippet" for same GraphQL call?
To do this in Postman, you hit the "</>" icon on right-side toolbar, then should be a drop down for the language to use. Pick "HTTP", and save that, then pick "cURL" and save that.

If you post the code snippet (excluding auth stuff and replace DNS names with example.com) here, I'm sure we can figure this out using /tool/fetch. That is your best option if need is in dhcp-client script.
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Tue May 07, 2024 11:14 pm

Sure. Here is in HTTP. I removed the domain and Bearer token.
POST /api/graphql HTTP/1.1
Host: example.com
{"query":"query search {inventory_model_field_data(general_search:\"000000000000\"){entities{inventory_item_id}}}","variables":{}}
And In CURL
curl -L -X POST 'example.com' -H 'Authorization: Bearer -H 'Content-Type: application/json' --data-raw '{"query":"query search {inventory_model_field_data(general_search:\"000000000000\"){entities{inventory_item_id}}}","variables":{}}'
Now If I try to run the same in Mikrotik like this,
:global datafile1 "{\"query\":\"query inventory{inventory_model_field_data(general_search:\"000000000000\"){entities{id}}}\"}"
:put ([/tool fetch url=$url http-method=post http-header-field="Content-Type:application/json, Authorization: $authorization" http-data=$datafile1 mode=https output=user as-value]->"data")
I just get an empty array response
[]
If I code in the "000000000000" in a variable It seems like it has an issue with the leading 0.
:global testname "000000000000"
:global datafile1 "{\"query\":\"query inventory{inventory_model_field_data(general_search:$testname){entities{id}}}\"}"
:put ([/tool fetch url=$url http-method=post http-header-field="Content-Type:application/json, Authorization: $authorization" http-data=$datafile1 mode=https output=user as-value]->"data")
I get the following response:
{"errors":[{"message":"Syntax Error: Invalid number, unexpected digit after 0: \"0\""}]}

If the value of $testname starts with 1 tho, it seems like it has no problem at all querying this info. I did multiple rounds of test to see if it was a length of the 0s or any other thing. The only answer I got is that it has a problem with the leading 0.
:global testname "100000000000"
:global datafile1 "{\"query\":\"query inventory{inventory_model_field_data(general_search:$testname){entities{id}}}\"}"
:put ([/tool fetch url=$url http-method=post http-header-field="Content-Type:application/json, Authorization: $authorization" http-data=$datafile2 mode=https output=user as-value]->"data")
and the response :
{"data":{"inventory_model_field_data":{"entities":[{"id":"832"}]}}
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Tue May 07, 2024 11:47 pm

Your HTTP example is useful. HTTP bodies do NOT need any escaping, but GraphQL must want the \" with your leading 0 case. And you can see that cURL use the single quotes, so quotes shouldn't need escaping there either.

So I think the issue is in RouterOS you need a "triple backsplash"... i.e. \\ to include the backslash in data and 3rd backslash for the double quote \".

e.g. This Postman HTTP version
{"query":"query search {inventory_model_field_data(general_search:\"000000000000\"){entities{inventory_item_id}}}","variables":{}}
becomes the following for RouterOS, using same example from Postman test.
:global httpdata "{\"query\":\"query search {inventory_model_field_data(general_search:\\\"000000000000\\\"){entities{inventory_item_id}}}\",\"variables\":{}}"
Basically adding outer double-quote " ...HTTP GQL data... " to the HTTP version from Postman, and then for any double quotes inside need a \ in front, as would any backslash \ need to be escape for RouterOS as \\. Also if the original query used a $ (that was NOT a routeros variable), that too need escaping from Postman's version, e.g. \$ as the prevent RouterOS from interpolating a local/global variable.

You'll note that in the cURL and HTTP ones, the data provided to GraphQL backend using search not inventory as the operand & Postman includes a empty variable list. Since your RouterOS work, likely these aren't at issues.

So if we take your existing query that works, other than the leading 0 problems, add the "triple backslash", it becomes (with a couple debug :put lines):

:global testname "000000000000"
:put "$testname $[:typeof $testname]"
:global datafile1 "{\"query\":\"query inventory{inventory_model_field_data(general_search:\\\"$testname\\\"){entities{id}}}\"}"
:put $datafile1
#check to make sure valid JSON...
:put [:serialize to=json [:deserialize from=json $datafile1]]
:put ([/tool fetch url=$url http-method=post http-header-field="Content-Type:application/json, Authorization: $authorization" http-data=$datafile1 mode=https output=user as-value]->"data")
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Wed May 08, 2024 12:35 am

FWIW, another way of building the GQL string is using RouterOS array to store it, and the use [:serialize] to convert RouterOS array to JSON, this avoid some of the more complex escaping (and uses a { } block so :local variables can be used at the CLI, since you'd want to use :local variables a final dhcp-client script:
{
:local searchtext "000000000"
:local gurl "...."
:local auth "...."
:local header "Content-Type:application/json, Authorization: $auth"
:local gql [:toarray ""]
:set ($gql->"query") "query inventory{inventory_model_field_data(general_search:\"$searchtext\"{entities{id}}}"
# or using variables, to do variables on the GQL backend....
#:set ($gql->"variables") [:toarray ""]
#:set ($gql->"variables"->"searchtext") $searchtext
#:set ($gql->"query") "query inventory{inventory_model_field_data(general_search: \$searchtext {entities{id}}}"
:local httpdata [:serialize to=json $gql]
:put $httpdata
:local fetched [/tool fetch url=$gurl http-method=post http-header-field=$header http-data=$httpdata mode=https output=user as-value]
:put $fetched
:local results [:deserialize from=json ($fetched->"data")]
:put $results
:put ($results->"data"->"inventory_model_field_data"->"entities"->0->"id")
}
 
saied
just joined
Topic Author
Posts: 17
Joined: Tue Mar 17, 2020 7:04 pm

Re: Can't Query Graphql site

Tue May 14, 2024 8:00 pm

Sorry for the late reply. Just wanted to tell you how much I appreciate you helping me out with all the issues I had. I am all good now. Thanks
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3617
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: Can't Query Graphql site

Tue May 14, 2024 9:44 pm

I suspect the \\\" fixed it in the string that's being sent. Since my 2nd example above using [:serialize to=json]* would NOT actually work for your 000000 case....

i.e. I learned something new here actually. Apparently [:serialize to=json] will automatically convert strings into numbers - even if the RouterOS type is a string and WITHOUT an explicit [:tonum] convertion. Specifically,
:put [:serialize to=json "0000000000"]       
0.000000
Note the string "0000000000" is parsed to a JSON floating point number, which break the example GraphQL since it for sure isn't expecting a floating point type.

Basically [:serialize] will parse a string type to see if it some kinda of number, and if it's a number it will make it a floating point type in the JSON. I didn't actually know this, but it does meaning floating point numbers can be expressed in JSON in a call to /tool/fetch. But does mean you CANNOT provide a string "00000000" to :serialize to get JSON from RouterOS variables/arrays - you building the GraphQL JSON in a string, with the needed escapes, is the right approach with "0000000" since the other end does want a string, not a number.

Just to document what happens using the [:serialize] approach – which work in 99.9% of normal use cases, just NOT if you needed "00000000" string in JSON ;)
# string that contain only ints or ".", become a floating point number type in JSON
:put [:serialize to=json "123"] 
      # 123.000000
:put [:serialize to=json "123.123"]
      # 123.123000
      
# and specifically to the OP's case...
:put [:serialize to=json "0000000000"]       
      0.000000 

# "num" RouterOS variable types, so remain ints
:put [:serialize to=json 123]       
      # 123
:put [:serialize to=json {a=123}]     
      # {"a":123}

# weird case, since 123.123 is an "ip" variable type in RouterOS...
# an IP address "pre-CIDR" could skip .0 in middle like :: in IPv6)....
# so this is correct since the JSON does not have an "ip" type, thus string
# and 123.123 is same IP address as more common 123.0.0.123 form, which likely be expected in most systems. 
:put [:serialize to=json 123.123]
      # "123.0.0.123"

* [:serialize to=json <variable>] takes an RouterOS variable/array and returns a string with JSON formatting of the provided variable/array

Who is online

Users browsing this forum: No registered users and 7 guests