Interacting with 3rd party REST services can quickly be done via "snakking".
You can snakk content from sockets or HTTP servers directly by calling these:
$msg snakk.json (url,verb,body,headers,result) : (payload)
$msg snakk.xml (url,verb,body,headers,result) : (payload)
$msg snakk.text (url,verb,body,headers,result) : (payload)
`result` is an optional name of a variable you want the result in, otherwise it goes to `payload`
Here's a sample POST (using oauth to get a token):
$when api.getAccessToken
=> snakk.json(
url="${AUTH_URL}",
verb="POST",
'Content-type'="application/x-www-form-urlencoded",
body="grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET_ENC}&resource=${RESOURCE}/"
)
=> (accessToken=payload.access_token)
The payload
result of snakk.json
is of type JSON and you can see the last expression extracts something from it (the access_token
) - see Structural expressions++ for details.
Content-Type
or Authorization
and others.
You should now use the headers
i.e. snakk.json(..., headers={Authorization:"nobody"})
Here's a sample GET (no verb or body needed):
$when annoy.the.googlenauts
=> snakk.json(
url="https://www.google.ca"
)
This is a very straight-forward way to send content to HTTP servers and receive and use content from them. For more advanced template based snakking, see below.
The main response from snakk is available as payload
with the appropriate type (string or json) and other details in this structure:
So that you can check response headers with snakk.response.headers.myHeader
.
Obsolete: in older versions you also had these values populated: snakkHttpResponse
, snakkHttpHeaders
, snakkHttpCode
.
Snakk will create errors if the response is not 200. To allow for specific codes, use:
=> snakk.json(
url="https://www.google.ca",
snakkHttpOptions={responseCode:"201"}
)
Or:
=> snakk.json(
url="https://www.google.ca",
snakkHttpOptions={responseCode:"*"}
)
The default timeout is 30 seconds. To change it, use readTimeout
:
=> snakk.json(
url="https://www.google.ca",
snakkHttpOptions={responseCode:"*",readTimeout:"60000"}
)
Note that readTimeout
is restricted and may require a paid plan.
This includes stuff like templates for sending and receiving content, automatically parsing values and other. Read on...
Alternatively, to control how the URL looks like, as well as the header attributes and content of the call, define a template with the same name as the message:
$msg subDb.load (subId) : (payload)
{{template subDb.load:request}}
GET http://localhost:9000/diesel/fiddle/react/subDb/load?subId=${subId}&resultMode=json
sso_token : joe 123456
{{/template}}
OR a POST
{{template subDb.load:request}}
POST http://localhost:9000/diesel/fiddle/react/subDb/load?subId=${subId}&resultMode=json
sso_token : joe 123456
body of post
{{/template}}
In the templates:
sso_token
For sending, you specify the Content-Type
as a template attribute. Also as a header attribute.
For receiving: first, the content-type
will be inspected, for known associations. If no content-type
was available, the content itself will be inspected to look for either "{..." or "<?xml...".
You can use xpath/jsonpath to introspect the replies, given:
$msg myservice.auth(account) : (success,msg)
These work:
{{template myservice.auth:response,content-type="application/xml",success=RESPONSE.TRANSUCCESS,msg=RESPONSE.TRANRESPMESSAGE}}
{{/template}}
or
{{template myservice.auth:response,content-type="application/xml",success=RESPONSE/TRANSUCCESS,msg=RESPONSE/TRANRESPMESSAGE}}
{{/template}}
or
$msg myservice.auth(account) : (success=xp:RESPONSE/TRANSUCCESS,msg)
or
$msg myservice.auth(account) : (success=RESPONSE.TRANSUCCESS,msg)
The response, as long as it can be identified as JSON or XML, will be parsed and the expression will be resolved, if possible.
Let's say we have a simple service which will add two numbers:
This is the actual service:
$mock demo.sum(p1,p2) => (sum=p1+p2)
And this is a new message, which will snakk the previous service, when invoked:
$msg <GET> demo.getsum(url="/diesel/wreact/Topic:Snakking_REST/react/demo/sum?resultMode=value&dfiddle=snak1&p1=a&p2=b", regex="/(?<sum>.*)/") : (sum)
This is another version, where we use a domain-level message, decomposed into a snakk:
$when demo.getsum2(p1,p2)
=> demo.getsum(url="/diesel/wreact/Topic:Snakking_REST/react/demo/sum?resultMode=value&dfiddle=snak1&p1="+p1+"&p2="+p2)
We will define a message to get the sum, which will "snakk" it from its url and then a test to actually run it and test the resulting sum.
Invoke the snakking message and verify results:
$send demo.getsum ()
$expect (sum is "ab")
$send demo.getsum2 (p1="c",p2="d")
$expect (sum is "cd")
When the test ran, it actually made a REST call to the backend to invoke demo.snakking.getsum
which in turn made another REST call to snakk the demo.snakking.sum
.
Easy?
$msg <GET> demo.snakking.sum(p1,p2,url="http://localhost:9000/diesel/fcall/func/Spec:fiddle?p1=aa&p2=b") : (sum)
$msg <GET> snakking.func(p1,p2,url="http://localhost:9000/diesel/fcall/func/Spec:fiddle?p1=aa&p2=b") : (sum)
This works for interacting with other diesel services, or any service that returns a simple json:
JSON content is default. The content must contain a normal diesel output and values will be located under values
. For instance, the result subId
could be found in this reply:
{
"values": {
"subId":"sub123456",
"name":"$name",
"address":"$address"
},
"failureCount":"0",
"errors": [ "Can't find the spec for rest.mcreate"],
"dieselTrace": {
"root": {
"children": [
...
as well as in this one:
{
"subId":"sub123456",
"name":"$name",
"address":"$address"
}
If the two methods above fail, you can use regex to identify output values. Use group names to identify value names. Pass the one regex via a parameter called surely enough, regex
.
The regex must match the entire reply (use lots of .
and *
) and have named capture groups and the names of the capture groups must match the return parms defined in the message signature. Here's a regex example with named group subId: (?<subId>\w+)
$msg<GET> c.op(url="http://localhost:9000/diesel/wiki/Spec:rest_spec/react/rest/mcreate?name=$name&address=$address&resultMode=json") : (subId, regex="/.*subId...(?<subId>\w+).,.*/")
With templates, use a regex template parm, which contains the regex, using the same named groups:
{{template ifttt.event1 regex=/(?<res>.*)/}}
These parms must also be listed as the result of the message, in the message spec.
If you already have some content and need to just parse it, these can help.
Parsing json:
$send snakk.parse.json
This will parse a string payload
into a JSON payload
.
Parsing regex:
$send ctx.set(payload="{\"status\":\"Failed\"}")
$send snakk.parse.regex (regex=/(?s)\{.*status":"(?<status>[^"]*)".*/)
$expect (status is "Failed")
This will attempt to parse the named groups into values with the same name and put them back in the same context.
You need to log in to post a comment!