Skip to content

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

StrategySemantics
equalsExact deep-equality. Every key-value pair must match the request verbatim.
containsSubset 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.
matchesRegular expression. Each value is treated as a Go regex pattern applied to the corresponding request value.
glob v3.12.0Glob 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:

yaml
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

yaml
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 headersResultReason
x-env=prod, x-user=alicematchbase ✓, alt[0] ✓
x-env=prod, authorization=Bearer admin_xmatchbase ✓, alt[1] ✓
x-env=staging, x-user=aliceno matchbase ✗
x-env=prodno matchbase ✓, 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:

LevelAffects
input.ignoreArrayOrderBase equals/contains/matches only
input.anyOf[i].ignoreArrayOrderThat alternative only
Not inheritedParent flag does not propagate into anyOf elements

Each anyOf element must set its own ignoreArrayOrder if needed.

yaml
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 irrelevant

Empty 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.