Im seeking a little help please. Curl -> fetch translation.

RouterOS Version=7.18.2

i have a script i wrote that interfaces with cloudflare API.
the api endpoint is # "https://api.cloudflare.com/client/v4/accounts/<your_account_id>/rules/lists/<your_list_id>/items"

I can push payloads to this api endpoint just fine everything works as expected via /tool fetch
I can also pulll data just fine from the api endpoint via /tool fetch

The issues is when i try to use method http-method=delete the issue is not with /tool fetch i just can not figure out how to escape and format the correct request via json in mikrotik.
how you would do this via curl is

 curl -X DELETE \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer "<your_api_token>" \
     -d '{"items": [{"id": "uuid_of_item_to_delete"}]}' \
      "https://api.cloudflare.com/client/v4/accounts/<your_account_id>/rules/lists/<your_list_id>/items"

Mikrotik $vars for reference

:local accountId "<your_account_id>"
:local listId "<your_list_id>"
:local apiToken "<your_api_token>"
## list item id  to be used in json payload.
:local ID 'e629fa7764a44ead90dd0d62bb9f9a66'
:local apitUrl ("https://api.cloudflare.com/client/v4/accounts/" . $accountId . "/rules/lists/" . $listId . "/items")

thank you to anyone who is willing to shed some light on this.
I should note that I use :deserialize to make the json easier to parse . With :deserialize and :serialize functions being so new and not yet documented in unsure how to use :serialize function to perform this task .

I have a website that converts a curl command (at least most of them & also limited to what fetch can do)

Click the “curl2rsc” link on https://tikoci.github.io/restraml
You can past in the curl command and pick a “format” (i.e. to variable or to screen etc).
It sometimes takes 30 seconds to run sometimes since the backend has to “warmup” since I use a free service for this. Future curl command should be converted quick after the initial


curl -X DELETE https://api.cloudflare.com/client/v4/accounts/$accountid/rules/lists/$listid/items -H "Content-Type: application/json" -H "Authorization: Bearer $apitoken"

For example, you get this from your curl above:


#		*** TIPS: Parsing JSON ***
#  Your request may return a JSON response.
#  RouterOS has support to parse the JSON string data returned into RouterOS array.
#  For example,
#	:global resp [/tool/fetch http-method=delete url="https://api.cloudflare.com/client/v4/accounts/\$accountid/rules/lists/\$listid/items" http-header-field=("Content-Type: application/json","Authorization: Bearer \$apitoken") as-value output=user]
#	:global json [:deserialize ($resp->"data") from=json]
#	:put $json

/tool/fetch http-method=delete url="https://api.cloudflare.com/client/v4/accounts/\$accountid/rules/lists/\$listid/items" http-header-field=("Content-Type: application/json","Authorization: Bearer \$apitoken")

The generated code escapes the sh variables, so you’d still need to define locals and remove the \ in the url= for them. So.

:local accountid "xxx"
:local listid "xxx"
:local apitoken "xxx"
/tool/fetch http-method=delete url="https://api.cloudflare.com/client/v4/accounts/$accountid/rules/lists/$listid/items" http-header-field=("Content-Type: application/json","Authorization: Bearer $apitoken")

BUT your issue is DELETE does not take a body… So my curl2rsc, correctly, does not include the “-d” part from your for a DELETE. You might want to check the Cloudflare’s docs, which has a different curl than yours:
https://developers.cloudflare.com/api/resources/rules/subresources/lists/

Specifically putting the list “item id” in URL is likely the main problem:
/accounts/{account_id}/rules/lists/{list_id}/items/{item_id}

And the converter should get you “close” to something that works in RouterOS.

1st off thank you for the reply..
i should have been more specific.

# "https://api.cloudflare.com/client/v4/accounts/$account_id/$list_id/items"    #is the api endpoint used. 
 "https://api.cloudflare.com/client/v4/accounts/$account_id/$list_id/items/$item_id"  # this endpoint is not used not valid.
 to use this endpoint  "https://api.cloudflare.com/client/v4/accounts/$account_id/$list_id/items"  # it expects a json request format like so
 
'{"items": [{"id": "e629fa7764a44ead90dd0d62bb9f9a66"}]}'

Mikrotik test

:local resp [/tool/fetch http-method=delete  url="https://api.cloudflare.com/client/v4/accounts/$accountId/rules/lists/$listId/items" http-data="{\"items\": [{\"id\": \"$id\"}]}"  http-header-field=("Content-Type: application/json","Authorization: Bearer   $apiToken") as-value output=user]
:local json [:deserialize ($resp->"data") from=json]
:log warning  $json

the issue is no matter how i try i can not get cloudflare endpoint to except the json request . fetch always results in error 400
I'm unsure on how to use Mikrotik scripting tools to produce a valid request the api endpoint will accept.

for reference i can make a request via curl and it works fine example#

 curl -X DELETE \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer <api_Token>" \
     -d '{"items": [{"id": "<Item_id>"}]}' \
      "https://api.cloudflare.com/client/v4/accounts/<account_id>/rules/lists/<list_id>/items"

I think the issue lies in how the request is formatted when in RouterOs. i have tried everything i can think off to produce a request the api endpoint will except.. i have no issue with the api working on a different platform.

on Mikrotik using the api endpoint i have no issue pushing data (writing/updating) to the api endpoint # example adding a item. or reading data from the api endpoint all that works.. only on with fetch http-method=delete there is a issue. then only difference are http-data="{"comment":"foo","name":"bar"}" # this will work to write data to the endpoint with http-method=get. But http-data="{"items": [{"id": "$id"}]}" # will fail using http-method=delete. i beleve it is a issue with then request http-data="{"items": [{"id": "$id"}]}".

added post for reference then api endpoint does take a body.

"https://community.cloudflare.com/t/delete-list-items-example-please/528757/8"

Your URL has spaces in it:

https://api.cloudflare.com/client/v4/accounts/ $accountId/rules/lists/$listId /items

so might want to try:

https://api.cloudflare.com/client/v4/accounts/$accountId/rules/lists/$listId/items

Now, according the HTTP 1.1 spec, I pretty sure a body is allowed with a DELETE, like GET.

But if curl takes it, IDK. And, I’d imagine MikroTik sends the http-body with a DELETE, there often less picky, but IDK for sure.

"https://api.cloudflare.com/client/v4/accounts/ $accountId/rules/lists/$listId /items"

was from an edit for public post to remove account values..

but anyway im lost @ this point. how to get the request to work.

And,
http-header-field=(“Content-Type: application/json”,“Authorization: Bearer apiToken”)
should be:
http-header-field=(“Content-Type: application/json”,“Authorization: Bearer $apiToken”)

[and maybe another cut-and-paste error, just saying]

And,
“({"items": [{"id": "$id"}]})”
like be
“{"items": [{"id": "$id"}]}”
without parentheses
or perhaps just, since items is in URL, it shouldn’t need items in body, but IDK the CF API…
“[{"id": "$id"}]”

All syntax $var issues where from hardcoded account values . And I replaced them with $var values for the post.

I have tried without the () in the http_data this was just a chuck of coded i did not check before posting sorry. All I know is I have make the request a mirror of the curl CMD that works and under MikroTik it does not .

What error code are you getting?

Error 400 for /tool fetch

That does suggest it’s the payload.

You can enabling logging in /system/logging, which will output the generated header etc to logs:

/system/logging/add action=memory topics=fetch

and then compare those with working curl if you add a “-v” for verbose logs … (and you can disable/remove after testing, since it does log a good bit)

But that 400 does suggest payload, since it’s not 404 or timeout… Typically most things convert to /tool/fetch, but the escaping can be tricky - one wrong thing and it’s invalid JSON… And it does seem CloudFlare’s docs could use an example, since that part is unclear other than your linked thread posting…now curl works which is good to know.

You can use :serialize to generate the JSON, which avoid needing escaping (or at least escaping JSON into RouterOS string):

:put [:serialize to=json {"items"={{"id"="$myidvariable"}}}]



{“items”:[{“id”:null}]}

so be something like http-data=[:serialize to=json {“items”={{“id”=“$myidvariable”}}}] in fetch avoid the " stuff… Now, you need the double parans {{ }} to make items a list of objects in JSON, RouterOS uses {} for both JSON arrays and objects with usage determining which, thus {{“varname”=“value”}} to get [{“varname”: “value”}] in JSON.

ok i enabled logging and can inspect header values.. its still a mystery as to why. all i gleamed is “{“success”:false,“errors”:[{“code”:10001,“message”:“Unable to authenticate request”}]}\n\r\n”

what is strange is this only happens with method=delete using the same API endpoint with fetch and method=get|post. to read or write data to api endpoint works with fetch. it is also strange that curl works fine also..


ok so the issue is very clear. method=delete does not send http-data=“” with the request and http-data= is only sent with method=post|put this results in the error.

looks like all have to do this on a down stream device.

thank you for your help.

Well, I’m half wrong. According to RFC specs for HTTP, DELETE with a message body is just discouraged and undefined – so my “does not” is wrong. But seems MikroTik is also under the same WRONG assumption that a message body is not allowed with a http-method=delete.

I tested /tool/fetch to nodejs test code this AM…and you’re right curl passes a message body (-d) just fine. And, /tool/fetch with a http-data= does NOT pass anything. That seems like a bug, since RouterOS should pass the http-data= — RouterOS just transparently passes in other cases (i.e. /tool/fetch does NOT enforce structure over message body other methods, so proviso in DELETE spec about “undefined” is not a problem).

note: filed a bug report (SUP-187198) with MiktoTik, since I agree with OP that http-method=delete should pass http-data=… And, that’s the root cause of the troubles here.

Thank you for all the help ! You have the pointers and hints to find what I was looking for on the MikroTik env. I’m new to MikroTik I am a Linux user so script and stuff In sh/bash are easy! But what have they done to the little Linux cored MikroTik’s interpreter is truly one of a kind ! I ended up just setting up a user and pulling the data I needed via ssh key based login to a Linux box and interacting with the API there .. if MikroTik ever fixes fetch I’ll use the script via MikroTik that “should then work” but really I don’t know if it works yet . Maybe so I will . As for what I was doing. Being able to update the CF WAF block or access rules on a domain pointing to the MikroTik. Utilizing the CF WAF to lessen the load on the MikroTik. Only having to sync a list and block everything else.

Actually, MikroTik did fix this. DELETE will now take a body in recent RouterOS.