Match Priority
When more than one mock could handle an incoming request, Mimic uses a scoring system to decide which one wins. The mock with the highest score is served. This lets you layer specific overrides on top of general fallback responses without rewriting your config.
The scoring rules
Section titled “The scoring rules”| Match component | Points |
|---|---|
| Exact method + path match | 1000 |
Path parameter match (:id, {id}) |
900 |
| Each matched query parameter | +100 |
| Each matched header | +50 |
| Request body match | +500 |
A mock has to match method and path to be considered at all — an exact path starts at 1000, a parameterized path (/users/:id) starts 100 points lower, at 900. From there, additional matchers add points on top, so more specific mocks score higher and beat less specific ones — an exact path with no other matchers (1000) still beats a pattern path with a matched header (900 + 50 = 950).
Exact-path candidates are looked up first (an O(1) hash lookup — no performance cost from having many pattern mocks around), and pattern candidates are only considered as a fallback. See Path Parameters for the full behavior, including how this interacts with sequences.
A request whose literal path matches nothing may still be served via trailing-slash tolerance — the match explanation on such a response notes trailing slash normalized, with no score penalty for taking that fallback.
Example: specific override on top of a fallback
Section titled “Example: specific override on top of a fallback”Imagine two mocks for GET /users:
mocks/users_default.json (fallback):
{ "method": "GET", "path": "/users", "status": 200, "response": { "users": [], "page": 1 }}Score for any matching request: 1000.
mocks/users_page_2.json (specific):
{ "method": "GET", "path": "/users", "status": 200, "query_params": { "params": { "page": "2" } }, "response": { "users": [{ "id": 3 }, { "id": 4 }], "page": 2 }}Score for a request that matches: 1000 + 100 = 1100.
Result:
GET /users→ only the first mock matches (nopageparam), returns the default.GET /users?page=2→ both mocks match, but the page-2 mock scores higher and wins.GET /users?page=99→ only the default mock matches, returns the default.
Example: tiered authentication
Section titled “Example: tiered authentication”Layered auth responses using header matching:
mocks/account_admin.json:
{ "method": "GET", "path": "/api/account", "status": 200, "headers": { "required": { "authorization": { "prefix": "Bearer " }, "x-role": "admin" } }, "response": { "role": "admin", "permissions": ["read", "write", "delete"] }}Score: 1000 + 50 + 50 = 1100.
mocks/account_user.json:
{ "method": "GET", "path": "/api/account", "status": 200, "headers": { "required": { "authorization": { "prefix": "Bearer " } } }, "response": { "role": "user", "permissions": ["read"] }}Score: 1000 + 50 = 1050.
mocks/account_unauthorized.json:
{ "method": "GET", "path": "/api/account", "status": 401, "response": { "error": "unauthorized" }}Score: 1000.
For a request with both an Authorization header and x-role: admin, all three mocks match. The admin mock has the highest score (1100) and wins. Drop the x-role header and the user mock (1050) wins. Drop the Authorization entirely and only the unauthorized mock matches.
Example: exact path overriding a pattern
Section titled “Example: exact path overriding a pattern”mocks/get_user_by_id.json (pattern, covers every id):
{ "method": "GET", "path": "/users/:id", "status": 200, "response": { "id": "{{path.id}}", "name": "Mock User" }}Score for any matching request: 900.
mocks/get_user_42.json (exact, special-cased):
{ "method": "GET", "path": "/users/42", "status": 200, "response": { "id": 42, "name": "VIP User", "vip": true }}Score for GET /users/42: 1000.
Result:
GET /users/42→ both mocks match, but the exact mock (1000) beats the pattern mock (900).GET /users/7→ only the pattern mock matches (no exact mock for7), returns the generic response.
This is the same idea as the pagination example above, just applied to the path itself instead of a query parameter.
Tie-breaking
Section titled “Tie-breaking”Equal scores are broken deterministically — the winner never depends on load order, so it stays the same across restarts and hot reloads:
- Most literal path segments first —
/users/:id(one parameter) beats/{resource}/:id(two parameters) for the same score. - Lowest
METHOD:pathkey, lexicographically. - Earliest position among mocks sharing that key — effectively, alphabetical-by-file-path load order (see Mock Files).
This makes ties predictable rather than an error to design around, but a mock that depends on winning a tie is still harder to reason about than one that doesn’t — adding a matcher to push the score apart remains the clearest way to make a mock’s precedence obvious at a glance.
Debugging match decisions
Section titled “Debugging match decisions”Set RUST_LOG=debug and watch the logs. Mimic logs the candidate mocks and their scores for each request:
DEBUG request GET /api/accountDEBUG candidates: 3DEBUG account_admin.json -> 1100 (selected)DEBUG account_user.json -> 1050DEBUG account_unauthorized.json -> 1000This makes it obvious when a mock isn’t winning the way you expected.