Using JSON Predicates
It is possible to match string
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.
JSON predicates follow the same semantics as those obeyed for multi-valued keys described on the
main predicates page, 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 any array element matches. deepEquals
will require all the values to match
(although the order isn't important).
Examples
Let's create an HTTP imposter. To show mountebank's first class support for JSON, we'll also
demonstrate passing a JSON object
as the http body
in the response. We've added a comment
field
to help explain each predicate. Like all unrecognized fields passed in, mountebank will
simply ignore it.
POST /imposters HTTP/1.1
Host: localhost:12382
Accept: application/json
Content-Type: application/json
{
"port": 4545,
"protocol": "http",
"stubs": [
{
"responses": [{
"is": {
"body": {
"code": "SUCCESS",
"author": "J.K. Rowling"
}
}
}],
"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"
}
]
}
]
}
We'll pass the following HTTP request to test the predicates and confirm we get the expected response:
POST / HTTP/1.1
Host: localhost:4545
{
"title": "Harry Potter",
"summary": "Dragons and a boy wizard"
}
HTTP/1.1 200 OK
Connection: close
Date: Thu, 09 Jan 2014 02:30:31 GMT
Transfer-Encoding: chunked
{
"code": "SUCCESS",
"author": "J.K. Rowling"
}
Embedded Arrays
mountebank uses the same logic to process arrays as he uses in other predicate operations, which can be summarized as follows:
- For all operators except
deepEquals
, at least one element in the array must match. The array syntax can be left off. - For
deepEquals
, all elements of the array have to match, in any order. - If you put an array in the predicate definition, all fields must match the array fields in the
request, in any order. For
deepEquals
predicates, the array lengths must also match.
These rules can be explored through the following example:
POST /imposters HTTP/1.1
Host: localhost:12382
Accept: application/json
Content-Type: application/json
{
"port": 4546,
"protocol": "http",
"stubs": [
{
"responses": [{
"is": {
"body": "Matched all elements exactly"
}
}],
"predicates": [
{
"deepEquals": {
"body": {
"books": [
{ "title": "The Hobbit" },
{ "title": "Game of Thrones" }
]
}
}
}
]
},
{
"responses": [{
"is": {
"body": "Matched all elements listed"
}
}],
"predicates": [
{
"equals": {
"body": {
"books": {
"title": "The Hobbit"
}
}
}
}
]
}
]
}
We'll pass the following HTTP request, leaving off Harry Potter so that all elements match the
deepEquals
predicate:
POST / HTTP/1.1
Host: localhost:4546
{
"books": [
{ "title": "Game of Thrones" },
{ "title": "The Hobbit" }
]
}
HTTP/1.1 200 OK
Connection: close
Date: Thu, 09 Jan 2014 02:30:31 GMT
Transfer-Encoding: chunked
Matched all elements exactly
DELETE /imposters/4545 HTTP/1.1
Host: localhost:12382
Accept: application/json
DELETE /imposters/4546 HTTP/1.1
Host: localhost:12382
Accept: application/json