rest-spec Pub

Message REST APIs and REST snakking

You will understand these better in conjunction with the test cases / examples of using these, in rest story++. Open them both in the fiddle here.

public:: (path ~path "/dieseltest/pub1")
   . (payload="My resource was: whatever")

0 public:: (path ~path "/dieseltest/pub2")
   . (payload="My resource was: whatever")

public:: (path ~path "/dieseltest/pub3")
   ctx.echo (payload ="My resource was: whatever"...="My resour...)

snakk and Just a simple echo service

Echo text - call this with diesel/rest/diesel/echoText:

$when:: (path ~path "/diesel/echoText")
   . (payload="ME:${} HEADERS: ${dieselHeaders}

BODY: ${payload}")
   ctx.echo (response=payload)

Interestingly, although sent with a verb of GET, Play will receive it as POST, if you put body in GET...

Echo JSON - call this with diesel/rest/diesel/echoJson:

$when:: (path ~path "/diesel/echoJson")
   . (payload={me:diesel[="cluster"][="me"],status:"echoJson",body:payload,verb:verb,headers:dieselHeaders})

A simple message

msg test.diesel.testAdditionFunc  (p1, p2)

Let's start with a simple mock message and then see how we can call it. This is the actual service implementation, it does a concatenation of two input parameters and returns that as a value named payload.

0 $mock:: test.diesel.testAdditionFunc (p1, p2)
   . (payload=(p1 + p2))

Simply because we defined it, we can now call it with a simple URL (note the name of the message in the URL below) like /diesel/react/test.diesel/testAdditionFunc?p1=hello&p2=world.

Now we will use this as a test bed and invoke it as a REST service from other messages.

How do templates work

Templates will not make a lot of sense until you look at the source of pages containing templates - so content

When you have a template with the same name as a message and type=request (see a few example below), when that message is invoked, the DieselEngine will make a direct HTTP call with that template, matching all parameters as well as it can.

Snakk with template and use the query parms to send

This is the actual service implementation, the one that does the addition. Simply by defining it, you can call it with a standard REST: /diesel/react/test.diesel/testAdditionFunc?p1=hello&p2=world.

Calling it with a request template

This is the message that is invoked by this test. It will call the functionality above because of the following template. You can call this message also with this URL: /diesel/react/test.diesel/testqueryp?p1=hello&p2=world.

msg POST test.diesel.testqueryp  (p1, p2)

When you click on this link, here's what happens (it's quite a few steps because of this particular test setup):

  • the engine figures out you wanted to call test.diesel.testqueryp and will "send" this message internally (i.e. create it and then process it)
  • while trying to process this message, the engine will find that the template below matches this message
  • the engine will execute the template as an HTTP call (this is the default protocol, but you can use others)
  • this will invoke the engine again, on the same server (via the URL), so in a separate context, now looking for test.diesel.testAdditionFunc, since this is what the template specified in the URL section
  • the other engine will find that message and execute it, passing it the parameters found in the request
  • the result is then returned to the first engine, as the response of the REST call
  • the first engine returns the response again, to the browser

This is the template used to execute the test.diesel.testqueryp message. Because the template has the same name as the message and it's of type request, the invocation of this message will result in the template execution via HTTP, i.e. making that POST and resulting in the other message being called.

{{template test.diesel.testqueryp:request}} (view)

Snakk by template, passing content in POST

Another example, where the functionality is called passing its parameteres as a JSON content, in a POST rather than query parms.

Calling it with a request template

This message will call the addition block because of the template below...

msg POST test.diesel.testjson  (p1, p2)

This is the template used to call it. Because the template has the same name and it's of type request the invocation of this message will result in the template execution via HTTP, i.e. making that POST and resulting in the other message being called.

The URL mapping is the diesel REST service and the reply is parsed as a "known diesel format".

{{template test.diesel.testjson:request}} (view)

Use a pattern to snakk

Just like above, here's the message and its request template:

msg POST test.diesel.testpattern  (p1, p2)

{{template test.diesel.testpattern:request}} (view)

Telnet snakking

Here's a simple curl-type call to an external socket, via a template:

msg telnet test.diesel.telnetGoogle 

In telnet templates that call HTTP services, make sure you include an empty line after GET - that's the HTTP spec...

{{template test.diesel.telnetGoogle:request protocol=telnet}} (view)

msg telnet test.diesel.telnetsample  (p1, p2)

This will fetch a result from an HTTP server, but by using a plain telnet socket connection rather than the HTTP protocol.

{{template test.diesel.telnetsample:request protocol=telnet}} (view)

A sample XML snakk (XML out XML in)

This will format the request out to another engine instance:

msg POST test.diesel.testXmlRequestOut  (p1, p2)

To find the other one, the XML in/out service, just invoke it by name: /diesel/mock/snakk.testXmlRequestService

{{template test.diesel.testXmlRequestOut:request,out:content-type="application/xml"}} (view)

Parse the response XML and extract one value:

{{template test.diesel.testXmlRequestOut:response:content-type="application/xml",sumxml=TX.SUMXML}} (view)

A sample REST XML service (XML in XML out)

This will receive the XML and parse it. Important to list the parsed values in message definition below:

msg POST test.diesel.testXmlRequestService  (p1, p2)

Need this rule - otherwise, not having anything else to do, it will try to snakk itself! This is the actual service logic.

$when:: test.diesel.testXmlRequestService
   . (sumxml=(p1 + p2))

Parse the incoming POST (note that the template URL doesn't match the message - it's a custom URL)

{{template test.diesel.testXmlRequestService:request,in:content-type="application/xml"}} (view)

Format the outgoing response. Response templates do not include the verb/url etc - just the content.

{{template test.diesel.testXmlRequestService:response:content-type="application/xml"}} (view)


A generic GET message

msg GET snakk.GET 

More template tests


Matching with a static path

msg public testdiesel.getdoc.pdf  (invoiceId)

0 $mock:: testdiesel.getdoc.pdf (invoiceId)
   . (payload=(("line197 - " + invoiceId) as "application/pdf"))


This template is used to request the PDF:

{{template test.getPdf:request}} (view)

This template will match the response:

{{template test.getPdf:response:content-type="application/pdf"}} (view)

Template matching with segments:

msg public test.getPdf2  (invoiceId)

0 $mock:: test.getPdf2 (invoiceId)
   . (payload=("line214 - " + invoiceId))

{{template test.getPdf2:request}} (view)

This forces the return type to pdf for a test.getPdf2 message.

{{template test.getPdf2:response:content-type="application/pdf"}} (view)

{{section pdfdoc:}}
%PDF-1.0 1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj xref 0 4 0000000000 65535 f 0000000010 00000 n 0000000053 00000 n 0000000102 00000 n trailer<</Size 4/Root 1 0 R>> startxref 149 %EOF

mail server example from main page

msg myMailServer.create  (user)

$when:: (path ~= "/myActualServer/create/(?<user>.+)")
   myMailServer.create (user)

We can mock a few examples of this service:

0 $mock:: myMailServer.create (user == "John@")
   . (payload={status:"Failed",error:"Illegal user name"})

0 $mock:: myMailServer.create (user == "John")
   . (payload={status:"Success"})

0 $mock:: myMailServer.create (user not defined)
   . (payload={status:"Failed",error:"Illegal user name"})


0 public:: (path ~path "/v1/:env/myResource/:resourceId/sleep")
   ctx.sleep (duration:Number=5000=5000)
   . (payload="My resource was: ${resourceId}")

Specific issue

val ret332:JSON={"a": 332}

$when:: (path ~= "/dieseltest/332")
   . (payload=ret332)

Was this useful?    

By: Razie | 2016-10-26 .. 2022-06-16 | Tags: spec , dsl , engine , private

Viewed 760 times ( | History | Print ) this page.

You need to log in to post a comment!

© Copyright DieselApps, 2012-2024, all rights reserved.