3

I'm trying to validate/match a request body against a JSON schema with Wiremock. AFAIK, Wiremock does not have first class support for schema validation, but only supports JSONPath.

Unfortunately, I can't wrap my head around the correct JSON-Path expression which would match valid request bodies.

Let's assume, I've an endpoint where you can POST/PATCH book titles. The following request body should be matched:

{
   "title": "Harry Potter and the Philosopher's Stone"
}

Easy with a JsonPath expression that looks for the title property.

Request bodies with additional properties, however, should NOT be valid. I don't know in advance which or how many additional properties clients will be sending, but the following documents should - for example - not match:

{
   "title": "Harry Potter and the Philosopher's Stone",
   "isbn": "0-7475-3269-9"
}
{
   "title": "Harry Potter and the Philosopher's Stone",
   "isbn": "0-7475-3269-9",
   "author": "J. K. Rowling"
}
{
   "title": "Harry Potter and the Philosopher's Stone",
   "xyz": "bla-bla-bla"
}

How should the JSON Path expression look like, so that only request bodies with only a title and nothing else are matched?

Or is there any other way apart from (misusing) JSONPath in Wiremock to achieve my goal?

WireMock uses Goessner's JSON-Path implementation under the hood, if that is of any significance

Stefan Haberl
  • 9,812
  • 7
  • 72
  • 81

1 Answers1

2

Depending on what you're trying to achieve, there are a few options.

If you need the match only the case where title == "Harry Potter and the Philosopher's Stone", and that is the only field in the JSON, you can simply do:

"bodyPatterns": [{
    "equalToJson": "{ \"title\": \"Harry Potter and the Philosopher's Stone\" }",
    "ignoreExtraElements": false
}]

The equalToJson property matches based on the request body being equivalent to your matcher. By adding the ignoreExtraElements property as false, it will ensure that you have an absolute match. I believe ignoreExtraElements defaults to true, so you have to explicitly set it to false.

If you need to match on any case where there is a title value, you'll want something like:

"bodyPatterns": [{
    "matchesJsonPath": "$.title"
}, {
    "matchesJsonPath": "$[?(@.size() == 1)]"
}]

In this example, we're checking that the body has some value for the title field, and then also checking that the entire body (referenced in JsonPath as $) has a size of 1. A breakdown of what the second matchesJsonPath symbols are doing:

  • $ -> root object (in this case, the entire request body)
  • ? -> denotes filter expression, requires parenthesis to wrap the expression
  • @ -> currently selected element (since we haven't drilled down from the root, it references the root)
agoff
  • 5,818
  • 1
  • 7
  • 20