Matching Logic
GripMock uses a declarative matching model built on four strategies and one composition operator. This page defines the formal semantics that apply identically to Input and Header matching.
Strategies
| Strategy | Semantics |
|---|---|
equals | Exact deep-equality. Every key-value pair must match the request verbatim. |
contains | Subset check. Objects are matched recursively and unlisted fields are ignored; arrays must carry all expected elements in any order; every other value, strings included, must be equal. Use matches or glob for partial strings. |
matches | Regular expression. Each value is treated as a Go regex pattern applied to the corresponding request value. |
glob v3.12.0 | Glob pattern (*, ?, [...]) applied to the corresponding request value. Every listed key must be present. |
Conjunction (AND)
Within one matcher block, all four strategies are AND-ed:
equals(request) AND contains(request) AND matches(request) AND glob(request)Empty/absent maps always pass (len == 0 → true), so in practice only the strategies you provide contribute to the result.
Example:
input:
equals:
role: "admin"
contains:
name: "jo"
matches:
email: "^[a-z]+@example\\.com$"Matches only when role is exactly "admin" and name contains "jo" and email matches the regex — all three must hold.
Disjunction (anyOf) v3.11.0
anyOf adds an OR layer on top of the base conjunction:
base(equals, contains, matches, glob) AND (anyOf[0] OR anyOf[1] OR ...)Each anyOf element is itself a conjunction (element.equals AND element.contains AND element.matches AND element.glob). At least one element must pass for the whole anyOf to pass.
If anyOf is empty or absent, only the base conjunction is evaluated.
anyOf is flat — no nested anyOf inside anyOf. Depth is exactly 1.
Example
headers:
equals:
x-env: "prod"
anyOf:
- equals:
x-user: "alice"
- matches:
authorization: "^Bearer admin_"Formula:
x-env == "prod" AND (
x-user == "alice" OR authorization ~= "^Bearer admin_"
)| Request headers | Result | Reason |
|---|---|---|
x-env=prod, x-user=alice | match | base ✓, alt[0] ✓ |
x-env=prod, authorization=Bearer admin_x | match | base ✓, alt[1] ✓ |
x-env=staging, x-user=alice | no match | base ✗ |
x-env=prod | no match | base ✓, alt[0] ✗, alt[1] ✗ |
ignoreArrayOrder
Controls whether arrays are compared as ordered sequences or as multisets: order stops mattering, but how many times an element appears still does.
Scoping rules:
| Level | Affects |
|---|---|
input.ignoreArrayOrder | Base equals/contains/matches only |
input.anyOf[i].ignoreArrayOrder | That alternative only |
| Not inherited | Parent flag does not propagate into anyOf elements |
Each anyOf element must set its own ignoreArrayOrder if needed.
input:
ignoreArrayOrder: true # affects base only
equals:
tags: ["grpc", "mock"]
anyOf:
- ignoreArrayOrder: true # required; not inherited
equals:
ids: ["a", "b"]
- matches:
name: "^admin_" # no arrays → flag irrelevantEmpty matchers
A stub with all empty matchers (equals: {}, contains: {}, and so on, no anyOf) acts as a catch-all — it matches any request. This is useful for fallback stubs with low priority. A matcher key written with no value at all is equivalent to {}.
Formal grammar
Matcher = Base AND AnyOf?
Base = Equals(Request) AND Contains(Request) AND Matches(Request) AND Glob(Request)
AnyOf = Alt[0] OR Alt[1] OR ...
Alt[i] = AltEquals(Request) AND AltContains(Request) AND AltMatches(Request) AND AltGlob(Request)Where each strategy returns true when its map is empty.
Related
- Input Matching — field-level details, arrays, nested objects
- Header Matching — multi-value headers, case sensitivity
- Stub Priority — how match score affects stub selection