Chapter 3: Dynamic responses

« Back to tutorials home

Prerequisites

To follow this chapter, you should first:

What are dynamic responses?

Responses are typically primed using the following interface in Traffic Parrot. There are similar interfaces for other protocols.

Priming a HTTP response

We refer to this request and response pair as a mapping. Traffic Parrot uses the request information in the mapping to determine whether an incoming request matches this mapping or not. If it does, then the response information in the mapping is sent as a response to the incoming request.

Mappings without dynamic responses

The typical way of working with a small number of mappings is to use exact request body matchers such as equalTo, equalToJson or equalToXml and specify a particular response body that should be the response for a particular request body.

For example, we could have exact equalToXml mappings for the following three XML request and response messages:

Interaction #1
<stockRequest>
    <checkId>1</checkId>
    <item>apple</item>
</stockRequest>
<stockResponse>
    <checkId>1</checkId>
    <date>2017-12-14T14:15:21Z</date>
    <item>apple</item>
    <available>4</available>
</stockResponse>
Interaction #2
<stockRequest>
    <checkId>2</checkId>
    <item>apple</item>
</stockRequest>
<stockResponse>
    <checkId>2</checkId>
    <date>2017-12-14T14:28:56Z</date>
    <item>apple</item>
    <available>0</available>
</stockResponse>
Interaction #3
<stockRequest>
    <checkId>3</checkId>
    <item>pear</item>
</stockRequest>
<stockResponse>
    <checkId>3</checkId>
    <date>2017-12-14T14:20:25Z</date>
    <item>pear</item>
    <available>5</available>
</stockResponse>

This can work well for a small number of mappings where we know what the request and response should look like ahead of time.

However, there are a number of limitations to this approach:
  • To support 1000 different responses we would need 1000 different mappings
  • There is no way to support random behaviour (e.g. we might want apples to be out of stock sometimes but not always)
  • There is no way to use parts of the request in the response (e.g. an id field)
  • There is no way to put the current date in the response

Mappings with dynamic responses

Dynamic responses are a way to avoid the limitations discussed above. We could simulate similar behaviour to the three interactions above using the following dynamic response:

<stockResponse>
    <checkId>{{xPath request.body '/stockRequest/checkId/text()'}}</checkId>
    <date>{{now format="yyyy-MM-dd'T'HH:mm:ssZ"}}</date>
    <item>{{xPath request.body '/stockRequest/item/text()'}}</item>
    <available>{{#ifEven (xPath request.body '/stockRequest/checkId/text()')}}0{{else}}5{{/ifEven}}</available>
</stockResponse>

We can use this as the response in a mapping with a simple matchesXPath matcher for the request that matches all the requests:

/stockRequest

Here is what some interactions look like as they are replayed:

Interaction #1 at 2018-01-08T14:15:21Z
<stockRequest>
    <checkId>1</checkId>
    <item>apple</item>
</stockRequest>
<stockResponse>
    <checkId>1</checkId>
    <date>2018-01-08T14:15:21Z</date>
    <item>apple</item>
    <available>4</available>
</stockResponse>
Interaction #2 at 2018-01-08T14:16:21Z
<stockRequest>
    <checkId>2</checkId>
    <item>apple</item>
</stockRequest>
<stockResponse>
    <checkId>2</checkId>
    <date>2018-01-08T14:16:21Z</date>
    <item>apple</item>
    <available>0</available>
</stockResponse>
Interaction #3 at 2018-01-08T14:17:21Z
<stockRequest>
    <checkId>3</checkId>
    <item>pear</item>
</stockRequest>
<stockResponse>
    <checkId>3</checkId>
    <date>2018-01-08T14:17:21Z</date>
    <item>pear</item>
    <available>5</available>
</stockResponse>
Interaction #4 at 2018-01-08T14:18:21Z
<stockRequest>
    <checkId>4</checkId>
    <item>orange</item>
</stockRequest>
<stockResponse>
    <checkId>4</checkId>
    <date>2018-01-08T14:18:21Z</date>
    <item>orange</item>
    <available>0</available>
</stockResponse>
We are now able to test many scenarios using a single mapping. We have a way to:
  • Send a request that will be unavailable by sending an even checkId
  • Send a request that will be available by sending an odd checkId
  • Always have the current date in the response
  • Repeat the same checkId from the request in the response
  • Repeat the same item name from the request in the response

Dynamic responses cookbook

The following section contains a number of common use cases for dynamic responses, with some ideas that you can copy and paste into your mappings and start using right away: If you were not able to find an example that works for you, please contact support@trafficparrot.com with details about the situation you are trying to mock or simulate.

Extracting an XML attribute from the request

This can be useful if we need to repeat some request attributes in the response. For example, let's say we need to support the following interaction:
<request id="123"/>
<response id="123"/>
We can achieve this using the following dynamic response:
<response id="{{xPath request.body '/request/@id'}}"/>

Extracting XML text from the request

This can be useful if we need to repeat some request text in the response. For example, let's say we need the following interaction:
<request>
    <id>100</id>
    <name>example</name>
</request>
<response>
    <id>100</id>
    <name>example</name>
</response>
We can achieve this using the following dynamic response:
<response>
    <id>{{xPath request.body '/request/id/text()'}}</id>
    <name>{{xPath request.body '/request/name/text()'}}</name>
</response>

Extracting JSON text from the request

This can be useful if we need to repeat some request text in the response. For example, let's say we need the following interaction:
{
    "type": "request",
    "id": 100,
    "name": "example"
}
{
    "type": "response",
    "id": 100,
    "name": "example"
}
We can achieve this using the following dynamic response:
{
    "type": "response",
    "id": {{jsonPath request.body '$.id'}},
    "name": "{{jsonPath request.body '$.name'}}"
}

Responding with an XML response element per request element

This can be useful if we need to simulate a response that processes request items and produces corresponding response items. For example, let's say we need the following interaction:
<request>
    <item id="1"/>
    <item id="2"/>
    <item id="3"/>
</request>
<response>
    <item id="1" status="OK"/>
    <item id="2" status="OK"/>
    <item id="3" status="OK"/>
</response>
We can achieve this using the following dynamic response:
<response>
    {{#each (xPathList request.body '/request') }}
        <item id="{{ xPath this '/item/@id' }}" status="OK"/>
    {{/each}}
</response>

Responding with a JSON response element per request element

This can be useful if we need to simulate a response that processes request items and produces corresponding response items. For example, let's say we need the following interaction:
{
    "type": "request",
    "items": [
        { "id": 1 },
        { "id": 2 },
        { "id": 3 }
    ]
}
{
    "type": "response",
    "items": [
        { "id": 1, "status": "OK" },
        { "id": 2, "status": "OK" },
        { "id": 3, "status": "OK" }
    ]
}
We can achieve this using the following dynamic response:
{
    "type": "response",
    "items": [
        {{#each (jsonPathList request.body '$.items') }}
            { "id": {{ jsonPath this '$.id' }}, "status": "OK" }{{#unless @last}},{{/unless}}
        {{/each}}
    ]
}

Inserting the current timestamp in a custom format

Sometimes the response must contain the current timestamp in a particular format. You can use the following kinds of dynamic responses to achieve this:
<date>{{now format="yyyy-MM-dd'T'HH:mm:ssZ"}}</date>
<date>{{now format="dd/MM/yyyy"}}</date>

Dynamic response file name based on request file name

File based processing often involves systems that consume request files and produce response files. Let's say we have files with names like:
  • SF001.REQ
  • SF002.REQ
  • SF003.REQ
And we want to produce files with corresponding names:
  • SF001.RSP
  • SF002.RSP
  • SF003.RSP
To do this, we can use the following dynamic response file name:
{{regex request.fileName '(.*).REQ' }}.RSP

IBM MQ different XML response tag based on a request attribute

Let us say you wanted to add a different tag to the IBM MQ response message body based on a request XML tag value. So for example when a request with a value starting with 90* is received, you will return one type of XML response tag, and otherwise, you will return a different XML tag in the response.

Request 1:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <GetFoo>
            <FooId>
                <BarId>102322323832</BarId>
            </FooId>
        </GetFoo>
    </soap:Body>
</soap:Envelope>
Expected response 1:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
        <RESPONSE_TYPE_10xxxxxxxxx/>
  </soap:Body>
</soap:Envelope>
Request 2:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <GetFoo>
            <FooId>
                <BarId>90374747436363</BarId>
            </FooId>
        </GetFoo>
    </soap:Body>
</soap:Envelope>
Expected response 2:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
        <RESPONSE_TYPE_20xxxxxxxxx/>
  </soap:Body>
</soap:Envelope>
We can do this by using this response body template:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    {{#equal (regex (xPath request.body '//GetFoo/FooId/BarId/text()') '(.{2})\d+') '90'}}
        <RESPONSE_TYPE_20xxxxxxxxx/>
    {{else}}
        <RESPONSE_TYPE_10xxxxxxxxx/>
    {{/equal}}
  </soap:Body>
</soap:Envelope>
Here is how it works:
  1. Extract the 'BarId' value of the request message body 'request.body'
  2. Apply a 'regex' and extract the first two characters of that value '(.{2})'
  3. Check if this value is equal to '90' by using the '#equal' block helper

Compatibility

Traffic Parrot currently supports dynamic responses for the following protocols: Please contact support@trafficparrot.com if you would like to see support for a protocol that is not yet listed here.

Next steps

  • Browse extensions documentation for more details on dynamic responses
  • Create some dynamic responses to use in your next test plan