Request Matching
Documentation / java / stubbing_and_verifying / request_matching
WireMock Cloud
WireMock enables flexible definition of a mock API by supporting rich matching of incoming requests. Stub matching and verification queries can use the following request attributes:
- URL
- HTTP Method
- Query parameters
- Form parameters
- Headers
- Basic authentication (a special case of header matching)
- Cookies
- Request body
- Multipart/form-data
- Client IP (as of WireMock version
3.13.0)
Here's an example showing all attributes being matched using WireMock's in-built match operators. It is also possible to write custom matching logic if you need more precise control:
Request with XML Body
stubFor(any(urlPathEqualTo("/everything"))
.withHeader("Accept", containing("xml"))
.withCookie("session", matching(".*12345.*"))
.withQueryParam("search_term", equalTo("WireMock"))
.withBasicAuth("jeff@example.com", "jeffteenjefftyjeff")
.withRequestBody(equalToXml("<search-results />"))
.withRequestBody(matchingXPath("//search-results"))
.withMultipartRequestBody(
aMultipart()
.withName("info")
.withHeader("Content-Type", containing("charset"))
.withBody(equalToJson("{}"))
)
.withClientIp(equalTo("127.0.0.1"))
.willReturn(aResponse()));
{
"request": {
"urlPath": "/everything",
"method": "ANY",
"headers": {
"Accept": {
"contains": "xml"
}
},
"queryParameters": {
"search_term": {
"equalTo": "WireMock"
}
},
"cookies": {
"session": {
"matches": ".*12345.*"
}
},
"bodyPatterns": [
{
"equalToXml": "<search-results />"
},
{
"matchesXPath": "//search-results"
}
],
"multipartPatterns": [
{
"matchingType": "ANY",
"headers": {
"Content-Disposition": {
"contains": "name=\"info\""
},
"Content-Type": {
"contains": "charset"
}
},
"bodyPatterns": [
{
"equalToJson": "{}"
}
]
}
],
"basicAuthCredentials": {
"username": "jeff@example.com",
"password": "jeffteenjefftyjeff"
},
"clientIp": {
"equalTo": "127.0.0.1"
}
},
"response": {
"status": 200
}
}
Request with Form Parameters
The following sections describe each type of matching strategy in detail.
URL matching
URLs can be matched either by equality or by regular expression. You also have a choice of whether to match just the path part of the URL or the path and query together.
It is usually preferable to match on path only if you want to match multiple query parameters in an order invariant manner.
Equality matching on path and query
Regex matching on path and query
Equality matching on the path only
Regex matching on the path only
Path templates
WireMock from 3.0.0 onwards supports matching on URL path templates conforming to the RFC 6570 standard.
When the path template URL match type is used this enables
- The ability to match path variables in the same way as query parameters, headers etc.
- The ability to reference path variables by name in response templates.
To match any request URL that conforms to the path template, you can do the following.
To further constrain the match to specific values of the path variables you can add match clauses for some or all of the variables in the path expression.
Matching other attributes
All request attributes other than the URL can be matched using the following set of operators.
Equality
Deems a match if the entire attribute value equals the expected value.
Case-insensitive equality
Deems a match if the entire attribute value equals the expected value, ignoring case.
Binary Equality
Deems a match if the entire binary attribute value equals the expected value. Unlike the above equalTo operator, this compares byte arrays (or their equivalent base64 representation).
Substring (contains)
Deems a match if the a portion of the attribute value equals the expected value.
Negative substring (does not contain)
Deems a match if the attribute value does not contain the expected value.
Regular expression
Deems a match if the entire attribute value matched the expected regular expression.
It is also possible to perform a negative match i.e. the match succeeds when the attribute value does not match the regex:
JSON equality
Deems a match if the attribute (most likely the request body in practice) is valid JSON and is a semantic match for the expected value.
With string literal:
Less strict matching
By default different array orderings and additional object attributes will trigger a non-match. However, both of these conditions can be disabled individually.
Placeholders
JSON equality matching is based on JsonUnit and therefore supports placeholders. This allows specific attributes to be treated as wildcards, rather than an exactly value being required for a match.
For instance, the following:
would match a request with a JSON body of:
It's also possible to use placeholders that constrain the expected value by type or regular expression. See the JsonUnit placeholders documentation for the full syntax.
JSON Path
Deems a match if the attribute value is valid JSON and matches the JSON Path expression supplied. A JSON body will be considered to match a path expression if the expression returns either a non-null single value (string, integer etc.), or a non-empty object or array.
Presence matching
Deems a match if the attribute value is present in the JSON.
Request body example:
Equality matching
Deems a match if the attribute value equals the expected value.
Request body example:
// matching
{ "things": { "name": "RequiredThing" } }
{ "things": [ { "name": "RequiredThing" }, { "name": "Wiremock" } ] }
// not matching
{ "price": 15 }
{ "things": { "name": "Wiremock" } }
Regex matching
Deems a match if the attribute value matches the regex expected value.
Request body example:
// matching
{ "things": { "name": "RequiredThing" } }
{ "things": [ { "name": "Required" }, { "name": "Wiremock" } ] }
// not matching
{ "price": 15 }
{ "things": { "name": "Wiremock" } }
{ "things": [ { "name": "Thing" }, { "name": "Wiremock" } ] }
Size matching
Deems a match if the attribute size matches the expected size.
Request body example:
// matching
{ "things": [ { "name": "RequiredThing" }, { "name": "Wiremock" } ] }
// not matching
{ "things": [ { "name": "RequiredThing" } ] }
Nested value matching
The JSONPath matcher can be combined with another matcher, such that the value returned from the JSONPath query is evaluated against it:
Since WireMock's matching operators all work on strings, the value selected by the JSONPath expression will be coerced to a string before the match is evaluated. This true even if the returned value
is an object or array. A benefit of this is that this allows a sub-document to be selected using JSONPath, then matched using the equalToJson operator. E.g. for the following request body:
The following will match:
JSON schema
Deems a match if the value conforms to the expected JSON schema.
By default the V202012 version of the JSON schema spec will be used, but this can be changed to one of V4, V6, V7, V201909, V202012 via the schemaVersion parameter.
stubFor(
post(urlPathEqualTo("/schema-match"))
.withRequestBody(matchingJsonSchema("{\n" +
" \"type\": \"object\",\n" +
" \"required\": [\n" +
" \"name\"\n" +
" ],\n" +
" \"properties\": {\n" +
" \"name\": {\n" +
" \"type\": \"string\"\n" +
" },\n" +
" \"tag\": {\n" +
" \"type\": \"string\"\n" +
" }\n" +
" }\n" +
"}"))
.willReturn(ok()));
(supported in 3.4+):
{
"request" : {
"urlPath" : "/schema-match",
"method" : "POST",
"bodyPatterns" : [ {
"matchesJsonSchema" : {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"schemaVersion" : "V202012"
} ]
},
"response" : {
"status" : 200
}
}
With string literal:
{
"request" : {
"urlPath" : "/schema-match",
"method" : "POST",
"bodyPatterns" : [ {
"matchesJsonSchema" : "{\n \"type\": \"object\",\n \"required\": [\n \"name\"\n ],\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"tag\": {\n \"type\": \"string\"\n }\n }\n}",
"schemaVersion" : "V202012"
} ]
},
"response" : {
"status" : 200
}
}
XML equality
Deems a match if the attribute value is valid XML and is semantically equal to the expected XML document. The underlying engine for determining XML equality is XMLUnit.
Use of placeholders
The XMLUnit placeholders feature is supported in WireMock. For example, when comparing the XML documents, you can ignore some text nodes.
When the actual request body is <message><id>123456</id><content>Hello</content></message>, it will be deemed a match.
If the default placeholder delimiters ${ and } can not be used, you can specify custom delimiters (using regular expressions). For example:
Excluding specific types of comparison
You can further tune how XML documents are compared for equality by disabling specific XMLUnit comparison types.
The full list of comparison types used by default is as follows:
ELEMENT_TAG_NAME
SCHEMA_LOCATION
NO_NAMESPACE_SCHEMA_LOCATION
NODE_TYPE
NAMESPACE_PREFIX
NAMESPACE_URI
TEXT_VALUE
PROCESSING_INSTRUCTION_TARGET
PROCESSING_INSTRUCTION_DATA
ELEMENT_NUM_ATTRIBUTES
ATTR_VALUE
CHILD_NODELIST_LENGTH
CHILD_LOOKUP
ATTR_NAME_LOOKUP
Same child nodes with different content
By default, WireMock takes into account an order of identical child nodes. Meaning if actual request has different order of same node on same level than stub it won't be matched.
As of WireMock version 3.7.0, this can be changed by passing additional argument to the equalToXml method
This will make sure that stub above matches both of following requests:
and If third argument is passed asfalse then first xml will not match the stub
Namespace awareness
To configure how XML namespaces are handled, as of WireMock
3.12.0, the namespaceAwareness property can be set.
.withRequestBody(equalToXml("<body>" +
" <entry>1</entry>" +
" <entry>2</entry>" +
"</body>").withNamespaceAwareness(EqualToXmlPattern.NamespaceAwareness.STRICT))
The available options for namespace awareness behaviour are STRICT, NONE and LEGACY.
STRICT adheres to strict XML namespace comparison.
Namespace prefixes must be bound to a namespace URI.
Namespace prefixes as well as namespace URIs must match (for both elements and attributes), unless explicitly excluded
by the exemptedComparisons parameter.
NONE does not consider XML namespaces when reading and comparing XML documents.
Namespace prefixes do not need to be bound to a namespace URI and are not considered a separate part of an
element/attribute name (i.e. the entire element/attribute name must match, not just the local name, regardless of
the exemptedComparisons parameter).
xmlns namespaced attributes are treated no differently to any other attribute.
LEGACY is not recommended and is only kept as an option for backwards compatibility.
XPath
Deems a match if the attribute value is valid XML and matches the XPath expression supplied. An XML document will be considered to match if any elements are returned by the XPath evaluation. WireMock delegates to Java's in-built XPath engine (via XMLUnit), therefore up to (at least) Java 8 it supports XPath version 1.0.
The above example will select elements based on their local name if used with a namespaced XML document.
If you need to be able to select elements based on their namespace in addition to their name you can declare the prefix to namespace URI mappings and use them in your XPath expression:
Nested value matching
The XPath matcher described above can be combined with another matcher, such that the value returned from the XPath query is evaluated against it:
If multiple nodes are returned from the XPath query, all will be evaluated and the returned match will be the one with the shortest distance.
If the XPath expression returns an XML element rather than a value, this will be rendered as an XML string before it is passed to the value matcher.
This can be usefully combined with the equalToXml matcher e.g.
Absence
Deems a match if the attribute specified is absent from the request.
Multipart/form-data
Deems a match if a multipart value is valid and matches any or all the multipart pattern matchers supplied. As a Multipart is a 'mini' HTTP request in itself all existing Header and Body content matchers can by applied to a Multipart pattern.
A Multipart pattern can be defined as matching ANY request multiparts or ALL. The default matching type is ANY.
Basic Authentication
Although matching on HTTP basic authentication could be supported via a
correctly encoded Authorization header, you can also do this more simply
via the API.
Dates and times
Dates and times can be matched in several ways. Three comparison operators are available: before, after and
equalToDateTime, all of which have the same set of parameters.
Additionally, the expected value can be either literal (fixed) or an offset from the current date. Both the expected and actual dates can be truncated in various ways.
Literal date/times
You can match an incoming date/time against a fixed value e.g. "match if the X-Munged-Date request header is after x":
Offset
You can also match in incoming value against the current date/time or an offset from it:
Local vs. Zoned
Both the expected and actual date/time values can either have timezone information or not. For instance a
date in ISO8601 format could be zoned: 2021-06-24T13:40:27+01:00 or 2021-06-24T12:40:27Z, or local: 2021-06-24T12:40:27.
Likewise a date/time in RFC 1123 (HTTP standard) format is also zoned: Tue, 01 Jun 2021 15:16:17 GMT.
Whether the expected and actual values are zoned or not affects whether they can be matched and how. Generally, the best approach is to try to ensure you're using the same on both sides - if you're expected a zoned actual date, then use one as the expected date also, plus the equivalent for local dates.
If the expected date is zoned and the actual is local, the actual date will assume the system timezone before the comparison is attempted.
If the expected date is local and the actual is zoned, the timezone will be stripped from the actual value before the comparison is attempted.
Date formats
By default these matchers will attempt to parse date/times in ISO8601 format, plus the three standard formats defined by HTTP RFCs 1123, 1036 and asctime (taken from C but also valid for specifying HTTP dates).
It is also possible to specify your own format using Java's date format strings.
Truncation
Both the expected and actual date/times can be truncated in various ways e.g. to the first hour of the day. When using offset from now as the expected date with truncation, the truncation will be applied first followed by the offsetting.
Truncation is useful if you want to create expressions like "before the end of this month" or "equal to the current hour".
It can usefully be combined with offsetting so e.g. if the match required is "after the 15th of this month" we could do as follows.
Truncating the actual value can be useful when checking for equality with literal date/times e.g. to say "is in March 2020":
The full list of available truncations is:
first minute of hourfirst hour of dayfirst day of monthfirst day of next monthlast day of monthfirst day of yearfirst day of next yearlast day of year
Order of applying offset and truncation
By default, the date/time truncation is applied first and the offset is applied afterwards. There are scenarios, though, where the order needs to be reversed. For instance, if we want to match with the last day of the next month then the truncation should be applied last. In this case the boolean property applyTruncationLast should be set to true:
In the example above setting the applyTruncationLast property to true means that the expected date/time value will first be offset by one month and only afterwards truncated to the last day of that month. Which in turn means that if the current date is September 1st then the expected date will first be offset to October 1st and only then truncated to October 31st. Had the applyTruncationLast property been false (the default value) then the resulting expected date would be October 30th, one day off the date we were aiming for.
Logical AND and OR
You can combine two or more matchers in an AND expression.
// Both statements are equivalent
stubFor(get(urlPathEqualTo("/and"))
.withHeader("X-Some-Value", and(
matching("[a-z]+"),
containing("magicvalue"))
)
.willReturn(ok()));
stubFor(get(urlPathEqualTo("/and"))
.withHeader("X-Some-Value", matching("[a-z]+").and(containing("magicvalue")))
.willReturn(ok()));
Similarly you can also construct an OR expression.
Combining date matchers as JSONPath/XPath sub-matchers
As an example of how various matchers can be combined, suppose we want to match if a field named date in a JSON request body
is a date/time between two points.
We can do this by extracting the field using matchesJsonPath then matching the result
of this against the before and after matchers AND'd together.
This would match the following JSON request body:
Matching Header/Query parameter containing multiple values
You can match multiple values of a query parameter or header with below provided matchers.
Exactly matcher exactly matches multiple values or patterns and make sure that it does not contain any other value.
There must be 3 values of id exactly whose values are 1, 2, and 3:
There must be 3 values of id exactly whose values conform to the match expressions
Includes matcher matches multiple values or patterns specified and may contain other values as well.
The values of id must include 1, 2, and 3:
Values of id must conform to the match expressions:
Logical NOT - negating matchers
You can negate any matcher using the logical NOT matcher.