src/views/docs/api/json.ejs
<%
title = 'json'
description = 'Using JSON in mountebank predicates'
%>
<%- include('../../_header') -%>
<h1>Using JSON Predicates</h1>
<p>It is possible to match <code>string</code> JSON fields using string operators, but mountebank finds
it clumsy, as you have to either exactly match the whitespace or use a regular expression. Given
mountebank's desire for elegance above all else, he supports predicates that treat JSON strings as
objects, allowing a fuller range of predicate matching.</p>
<p>JSON predicates follow the same semantics as those obeyed for multi-valued keys described on the
<a href='/docs/api/predicates'>main predicates page</a>, like those observed when a querystring has
the same key multiple times. Since the selected JSON field can potentially represent an array, most predicates
match if <em>any</em> array element matches. <code>deepEquals</code> will require all the values to match
(although the order isn't important).</p>
<h2>Examples</h2>
<p>Let's create an HTTP imposter. To show mountebank's first class support for JSON, we'll also
demonstrate <a href='/docs/protocols/http#inline-json-response-bodies'>passing a JSON object
as the <code>http body</code></a> in the response. We've added a <code>comment</code> field
to help explain each predicate. Like all unrecognized fields passed in, mountebank will
simply ignore it.</p>
<testScenario name='json'>
<step type='http'>
<pre><code>POST /imposters HTTP/1.1
Host: localhost:<%= port %>
Accept: application/json
Content-Type: application/json
{
"port": 4545,
"protocol": "http",
"stubs": [
{
"responses": [{
"is": {
"body": <strong class='highlight1'>{
"code": "SUCCESS",
"author": "J.K. Rowling"
}</strong>
}
}],
"predicates": [
{
"equals": { "body": { "title": "Harry Potter" } },
"caseSensitive": true,
"comment": "case sensitivity applies to the key as well as the value"
},
{
"equals": { "body": { "title": "POTTER" } },
"except": "HARRY ",
"comment": "The except regular expression is removed from the value before matching"
},
{
"matches": { "body": { "title": "^Harry" } }
},
{
"exists": { "body": { "title": true } },
"comment": "The given JSON key must exist"
},
{
"exists": { "body": { "name": false } },
"comment": "The given JSON key must NOT exist"
}
]
}
]
}</code></pre>
</step>
<p>We'll pass the following HTTP request to test the predicates and confirm we get the
expected response:</p>
<step type='http'>
<pre><code>POST / HTTP/1.1
Host: localhost:4545
{
"title": "Harry Potter",
"summary": "Dragons and a boy wizard"
}</code></pre>
<assertResponse>
<pre><code>HTTP/1.1 200 OK
Connection: close
Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
Transfer-Encoding: chunked
<strong class='highlight1'>{
"code": "SUCCESS",
"author": "J.K. Rowling"
}</strong></code></pre>
</assertResponse>
</step>
<h3>Embedded Arrays</h3>
<p>mountebank uses the same logic to <a href='/docs/api/predicates#array-match'>process arrays</a> as he
uses in other predicate operations, which can be summarized as follows:</p>
<ul class='bullet-list'>
<li>For all operators except <code>deepEquals</code>, at least one element in the array must match.
The array syntax can be left off.</li>
<li>For <code>deepEquals</code>, all elements of the array have to match, in any order.</li>
<li>If you put an array in the predicate definition, all fields must match the array fields in the
request, in any order. For <code>deepEquals</code> predicates, the array lengths must also match.</li>
</ul>
<p>These rules can be explored through the following example:</p>
<step type='http'>
<pre><code>POST /imposters HTTP/1.1
Host: localhost:<%= port %>
Accept: application/json
Content-Type: application/json
{
"port": 4546,
"protocol": "http",
"stubs": [
{
"responses": [{
"is": {
"body": "<strong class='highlight1'>Matched all elements exactly</strong>"
}
}],
"predicates": [
{
"deepEquals": {
"body": {
"books": [
{ "title": "The Hobbit" },
{ "title": "Game of Thrones" }
]
}
}
}
]
},
{
"responses": [{
"is": {
"body": "<strong class='highlight2'>Matched all elements listed</strong>"
}
}],
"predicates": [
{
"equals": {
"body": {
"books": {
"title": "The Hobbit"
}
}
}
}
]
}
]
}</code></pre>
</step>
<p>We'll pass the following HTTP request, leaving off <em>Harry Potter</em> so that all elements match the
<code>deepEquals</code> predicate:</p>
<step type='http'>
<pre><code>POST / HTTP/1.1
Host: localhost:4546
{
"books": [
{ "title": "Game of Thrones" },
{ "title": "The Hobbit" }
]
}</code></pre>
<assertResponse>
<pre><code>HTTP/1.1 200 OK
Connection: close
Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
Transfer-Encoding: chunked
<strong class='highlight1'>Matched all elements exactly</strong></code></pre>
</assertResponse>
</step>
<step type='http'>
<code class='hidden'>DELETE /imposters/4545 HTTP/1.1
Host: localhost:<%= port %>
Accept: application/json</code>
</step>
<step type='http'>
<code class='hidden'>DELETE /imposters/4546 HTTP/1.1
Host: localhost:<%= port %>
Accept: application/json</code>
</step>
</testScenario>
<%- include('../../_footer') -%>