We use templates to parse HTTP requests and replies, in/out over HTTP. Let's take a look.
Note: read REST Microservices++ first. Templates are not really neccessary and a just a prototype at this point.
The first thing to understand is that a particular message can be either incoming (i.e. receiving your HTTP request) or an outgoing (i.e. sending an HTTP request to a 3rd party service, but currently, it cannot be both.
If you need to simulate a message for both, like a proxy, then use an in message mapped to an out message and then each can have a different formatting template:
$msg my.api (id,transactiontype,authtype,account,exp,amt,systemcode)
$msg my.api.out (id,transactiontype,authtype,account,exp,amt,systemcode)
$when my.api (id,transactiontype,authtype,account,exp,amt,systemcode)
=> my.api.out (id,transactiontype,authtype,account,exp,amt,systemcode)
This establishes a simple route / rule to map the "in" to the "out" and it looks like the message is both in/out.
So, each message can have one request
and one response
template. Depending on the message being used as in/out, there are thus four usages of templates (some templates are used to format a message and some are used to parse a message:
We attempted to use similar templates for all of these.
One way to control the response properties is to set them at the root level:
$when diesel.rest (path ~path "/v1/ems/:env/device/:deviceType/:deviceId", verb == "GET")
=> (dieselRoot["diesel.http.response.contentType"] = "application/json")
=> (dieselRoot["diesel.http.response.status"] = 512)
=> (payload = "meh, is this csv or error?")
This can also be achieved from anywhere inside the flow with the diesel.flow.return
message:
$when diesel.rest (path ~path "/v1/ems/:env/device/:deviceType/:deviceId", verb == "GET")
=> diesel.flow.return(
diesel.http.response.contentType = "application/json",
diesel.http.response.status = 512
payload = "meh, is this csv or error?")
You can define either a pattern or specific xml/json templates for requests.
Here's a sample of a pattern template. Note that it looks like an XML, but in fact it is a pattern - note the (...)?
optional blocks:
{{template my.api:request}}
POST ${URL}
content-type: application/xml
<TRANSACTION>
<ID>${id}</ID>
<TRANSACTIONTYPE>${transactiontype}</TRANSACTIONTYPE>
(<AUTHTYPE>${authtype}</AUTHTYPE>)?
<ACCOUNT>${account}</ACCOUNT>
<EXP>${exp}</EXP>
(<AMT>${amt}</AMT>)?
(<SYSTEMCODE>${ccsystemcode}</SYSTEMCODE>)?
<ENCODING>UTF-8</ENCODING>
</TRANSACTION>
{{/template}}
This is used to match the incoming message as regex and extract the respective parameters. This is very well suited to parsing plain text.
Note that if your xml would have the tags in a different order, they won't match anymore! Use the XML template below for that!
Also, any optional tags, need to be put inside an optional non-named capture group, as AMT above.
Add the content type for the template, to turn it into an XML matcher. Note that the template does not look much different, except the request matcher will not match it as text, but will parse the XML tags and match them one by one.
This is parsing by example - you mark the values you're interested in and the parser figures out how to extract them.
Note the content-type="application/xml"
on the template definition, that's the important one, this indicates that the template itself should be interpreted as an XML template.
{{template my.api:request:content-type="application/xml"}}
POST ${URL}
content-type: application/xml
<TRANSACTION>
<ID>${id}</ID>
<TRANSACTIONTYPE>${transactiontype}</TRANSACTIONTYPE>
<AUTHTYPE>${authtype}</AUTHTYPE>
<ACCOUNT>${account}</ACCOUNT>
<EXP>${exp}</EXP>
<AMT>${amt}</AMT>
<SYSTEMCODE>${ccsystemcode}</SYSTEMCODE>
<ENCODING>UTF-8</ENCODING>
</TRANSACTION>
{{/template}}
There is another method to parse incoming XML (and JSON) documents, using parameter sourcing lists, like so:
{{template my.api:request:content-type="application/xml",ID=TRANSACTION.ID, AMT=TRANSACTION.AMT}}
POST ${URL}
content-type: application/xml
no body
{{/template}}
In this case, the template needs no body (since it's used for parsing) and the parameter list is evaluated, to extract values. Note that you must still respect the HTTP template format, so it can be parsed (start with a verb, url, followed by two empty lines).
JSON parsing is similar to xml, just use the content-type:application/json
instead. You have both the parse by example and extract with expression options as well.
This is an example of an outgoing template which will post a form and parse the result:
$msg microsoft.getAccessToken : (accessToken)
{{template microsoft.getAccessToken:request accessToken=access_token}}
POST https://login.microsoftonline.com/${ACCESS_ID}/oauth2/token
Content-type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&resource=${RESOURCE}
{{/template}}
This will use the ${ACCESS}
and ${CLIENT_ID}
etc parameters to format the outgoing request and then will parse the incoming request (will automatically detect that it's a JSON document) and extract the accessToken
from it.
You need to log in to post a comment!