Simula Template Scriptlets

Overview

definition

Scriptlets are template fragments that can produce variable content. They are practically code.

The Simula template engine executes the scriptlets code upon rendering the template. The code may produce output or drive its production by using, for example, control statements (loops, if…​else, etc.).

Let’s not get into a debate around logic-less templates vs. templates that may contain explicit logic. The Simula templating engine does support scriptlets and you may as well take advantage of this powerful feature, if you need it.

Syntax

Currently, scriptlet’s code is code in the Groovy scripting language. Don’t worry if learning a new scripting language isn’t on your to-do list - a little experience in any other programming language will be more than enough to make you feel comfortable writing statements in Groovy to simulate parts of API responses. And again - only if you need to.

The syntax for a scriptlet is

<%
  Groovy-language-scripting-statements
%>

The delimiters - <% and %> - can be configured to be something different.

It is to note that it isn’t possible to have nested scriptlets, that’s it - a scriptlet inside another scriptlet, or a scriptlet inside a ${ …​ } placeholder.

Scriptlets in the Body

Let’s look at the following simlet example to demonstrate some of the aspects of using scriptlets. The comments in the scriptlet code provide additional information (even for things that may be obvious):

matchers:
- where: method
  equals: GET

- where: UriPath
  equals: "/api/places/nearby"

- where: uriQueryParameter
  named: "postalCode"
  equals: "54321"

- where: uriQueryParameter
  named: "radius"
  equals: "10"

# At least one query string parameter with name 'placeType' and value 'restaurant'
- where: uriQueryParameter
  named: "placeType"
  equals: "restaurant"


QueryStringParms:
  is: parameter
  from: uriQueryParameters

OriginHeaderParm:
  is: parameter
  from: header
  named: "Origin"


response:
  from: template
  template: Simula
  # Optional field for the template scriptlets language.
  # It currently must be 'groovy', if field is specified
  lang: groovy

  status: 200
  headers:
  - "Content-Type: application/json; charset=UTF-8"

  # Configuration for optional header field - no name or value are
  # to be output unless some condition is met. Requirements:
  # > The header field value must end with "\r\n" line break;
  # > Set 'optional: true':
  - header: "<% if (${OriginHeaderParm} != null && ${OriginHeaderParm.trim().length()} > 0) { %>Allow-Origin: ${OriginHeaderParm}\r\n<% } %>"
    # "optional" is needed because at the time the template is constructed, it is
    # unknown if the header field name and value will be empty or not when resolved.
    # (The template placeholder resolving process doesn't know what is what). So,
    # can't add "\r\n" line break automatically when needed but it is not present.
    optional: true

  body: |+
    {
      "queryStringParms": {
        "total": ${ QueryStringParms.size() },
        "postalCode": "${ QueryStringParms['postalCode'][0] }",
        "placeType": [
          <%
            // Single-line comment in the scriptlet
            /*
              Multi-line
              comment
            */

            // Defining a local variable. It is visible in all scriptlets of this template
            // Here, ${...} surrounds QueryStringParms to denote it is a placeholder
            placeTypeParms = ${ QueryStringParms['placeType'] }

            // Loop over the collection of 'placeType' query string parameter values
            for (i = 0; i < placeTypeParms.size(); i++)
            {
              // Adding semicolon ';' at the end is required only
              // when using multiple statements on the same line
              placeTypeValue = placeTypeParms[i];

              if (i > 0)
              {
                // Mixing scriptlet code with direct text output
                // Line break followed by spaces to achieve pretty printing
                %>,\n      <%
              }

              // Writing out the result of string concatenation.
              // Parenthesis () are optional
              write ('"' + placeTypeValue + '"')
            }
          %>
        ],
        <%
          /*
            This is a scriptlet with a multi-line comment only and no other code.

            It actually causes one empty line in the output because of
            where its left and right delimiters appear with respect to
            the text surrounding it.

            The scriptlet below to produce value for "isDebug1"
            doesn't use ${...} to denote it is a placeholder.
          */
        %>
        "isDebug1": <% if (QueryStringParms['debug'] != null) { %>true<% } else { %>false<% } %>,
        "isDebug2": <%
          // Ternary operator. Also, this shows coercing
          // of non-null object references to true
          write (QueryStringParms['debug'] ? true : false)
        %>
      }
    }

The following HTTP request

GET /api/places/nearby?postalCode=54321&radius=10&placeType=restaurant&placeType=cafe&debug

will be matched by the matchers defined in the simlet above. This is then the body of the HTTP response produced after rendering the template:

{
  "queryStringParms": {
    "total": 4,
    "postalCode": "54321",
    "placeType": [
      "restaurant",
      "cafe"
    ],

    "isDebug1": true,
    "isDebug2": true
  }
}

Scriptlets in Header Fields

Scriptlets can be used not only in the HTTP response body definition but also in header field configuration.

The following example demonstrated the configuration of a conditional header field - header field that is output only when some condition is met:

#...

OriginHeaderParm:
  is: parameter
  from: header
  named: "Origin"


response:
  from: template
  template: Simula

  status: 200
  headers:
  - "Content-Type: application/json; charset=UTF-8"

  # Configuration for optional header field - no name or value are
  # to be output unless some condition is met. Requirements:
  # > The header field value must end with "\r\n" line break;
  # > Set 'optional: true':
  - header: "<% if (OriginHeaderParm != null && OriginHeaderParm.trim().length() > 0)
                { %>Access-Control-Allow-Origin: ${OriginHeaderParm}\r\n<% } %>"
    # "optional" is needed because at the time the template is constructed, it is
    # unknown if the header field name and value will be empty or not when resolved.
    # (The template placeholder resolving process doesn't know what is what). So,
    # can't add "\r\n" line break automatically when needed but it is not present.
    optional: true

  #...

There is a lot more that scriptlets can do. They give you extreme power and flexibility in modeling API simulation responses.


We would love to hear your feedback! Shoot us a quick email to [feedback at APISimulator.com] to let us know what you think.

Happy API Simulating!