WireMock alternative: mock an OpenAPI spec without writing stubs
Dieser Artikel ist nicht übersetzt. Ihr lest ihn in der Sprache, in der er geschrieben wurde.
You have an OpenAPI spec and you need a mock server. WireMock is what most people find first. Fifteen years old, and already installed at every Java shop you have worked in. So you start the container and point it at your spec.
It will not read it.
That is not a bug and nobody forgot. WireMock's unit of work is a stub, which is one request matcher plus one canned response, and a spec is not a stub. If you are here looking for a WireMock alternative, that gap is usually the reason. Below, both tools run the same API on the same laptop. WireMock still wins three things, and they are at the end.
Does WireMock support OpenAPI?
Not in the open source version, and it never has.
The API is Twilio Verify: 29 paths, 53 operations, 169 KB of YAML. Put it where WireMock keeps its stubs.
wiremock/
mappings/
openapi.ymldocker run -d -p 8080:8080 -v "$PWD/wiremock:/home/wiremock" wiremock/wiremock:3.13.2The container comes up fine. It also loaded nothing.
$ curl -s localhost:8080/__admin/mappings | jq .meta
{ "total": 0 }
$ curl localhost:8080/v2/Services
No response could be served as there are no stub mappings in this WireMock instance.WireMock reads .json files out of that directory and ignores everything else, so your spec sat there in silence. Convert it to JSON, which is the obvious next thing to try, and the container stops starting at all:
Exception in thread "main" com.github.tomakehurst.wiremock.standalone.MappingFileException:
Error loading file /home/wiremock/./mappings/openapi.json:
Unrecognized field "openapi" (class ...StubMappingCollection), not marked as ignorableopenapi is an unrecognized field.
None of this is an accident. OpenAPI import is a WireMock Cloud feature, and the open source version has never had it. Somebody asked for it in August 2018, and the answer came the next morning from WireMock's own creator:
I don't have any plans to open source MockLab's implementation at the moment. I'd suggest if you want to work on this that you make it an extension.
MockLab was the earlier name of WireMock Cloud. Eight years on, the feature is still on the other side of that line.
What WireMock stub mappings cost per endpoint
One JSON file per stub. This one covers a single Twilio Verify endpoint and follows the documentation:
{
"request": { "method": "GET", "urlPath": "/v2/Services" },
"response": {
"status": 200,
"headers": { "Content-Type": "application/json" },
"jsonBody": {
"services": [
{
"sid": "VA7AF5B1C9823Bb1D02f75Bd63096D7094",
"account_sid": "ACa5D9aF1ab80f9f33AB86FF9B2DD023dA",
"friendly_name": "checkout-otp",
"code_length": 6,
"lookup_enabled": true,
"date_created": "2026-01-01T04:51:57Z",
"url": "https://verify.twilio.com/v2/Services/VA7AF5"
}
],
"meta": { "page": 0, "page_size": 50, "key": "services" }
}
}
}That is 25 lines and it covers one operation out of 53. Ask for the next path along and you get this:
$ curl localhost:8080/v2/Services/VA7AF5
Request was not matchedSo the cost of this API is 53 of those files, and every field in every one of them is a shape you looked up by hand and typed. Twilio Verify is a small API. GitHub's public API description is 551 paths and 845 operations.
There is a second cost that shows up later. Your spec and your stub mappings are now two descriptions of the same API, maintained by different people at different times, and only one of them is what your service implements. The WireMock ecosystem knows this. Somebody has published a GitHub Action called WireMock OpenAPI Validator whose entire job is to check stub mappings against a spec in the PR pipeline, and it describes itself as "perfect for ensuring your mocks stay in sync with your API contracts".
An OpenAPI mock server that reads the spec directly
Mockzilla takes the file you already have.
services/
verify/
openapi.ymlmockzilla services/All 53 operations answer, on a URL shaped like the folder: /verify/v2/Services. There is no mapping format, no matcher syntax and no config file. The folder name is the mount path and the spec is the contract.
Keeping the spec at runtime gives you something a stub server cannot. Switch validation on and the simulation checks traffic against the document: a request that breaks the schema comes back 400, a response that breaks it comes back 500. Per request that is one header.
curl -X POST "$BASE/openai/chat/completions" \
-H "content-type: application/json" \
-H "X-Mockzilla-Validate-Request: true" \
-d '{"model": 123, "messages": [{"role": "user", "content": "hi"}]}'{
"error": "request validation failed",
"details": [{
"validationErrors": [
{ "reason": "got number, want string", "fieldPath": "$.model" }
]
}]
}model is declared as a string, so the call never reaches the generator. Your mock just caught a bug in your client. On the WireMock side, that check is what the validator action bolts on from outside.
Both tools in Docker, same machine, same API, three runs each:
| Mockzilla | WireMock | |
|---|---|---|
docker run to first response | 180 to 295 ms | 657 to 806 ms |
| Memory, warm | 35 MiB | 182 MiB |
| Endpoints answering | 53 | 1 |
The 182 MiB is WireMock's floor rather than the price of that one stub, and the startup number is mostly the JVM booting. Those are the running costs of a mature Java library that also works standalone. The project is in good health: version 3.13.2 shipped in November 2025 and version 4 has been in beta since June 2026.
Mocking one endpoint, side by side
Forget specs for a moment. You want GET /foo to answer with a bit of JSON. Everything you create, in each tool:
WireMock wants a stub mapping, in mappings/:
{
"request": { "method": "GET", "url": "/foo" },
"response": {
"status": 200,
"headers": { "Content-Type": "application/json" },
"jsonBody": { "id": 1, "name": "thing" }
}
}Mockzilla wants the body, in a folder shaped like the URL:
services/
api/
foo/index.json{ "id": 1, "name": "thing" }Both answer 200 with that JSON. To write the first you had to know that jsonBody nests inside response, and that the matcher key is url. To write the second you had to know where /foo goes.
It holds as you add to it:
| To mock | WireMock | Mockzilla |
|---|---|---|
POST /foo as well | a second mapping file | foo/post/index.json |
GET /foo/{id} | "urlPathPattern": "/foo/([^/]+)" | a folder named {id} |
GET /foo returning 404 | "status": 404 in the mapping | not on a static file |
That last row is a real limit. A static response always answers 200. Non-200s come from the spec, which knows which codes the endpoint declares, or from the error rules in config.yml. WireMock can set a status on any stub, and the envelope is what it charges for that.
Nothing above needs a spec. Drop the folder in on its own and those routes exist, which is the case a WireMock user is usually in: no OpenAPI document, just a dependency that has to answer something.
Overriding one endpoint of a spec
This one has no WireMock column. It is also what makes a generated mock usable in a real test suite.
Generated data fits the schema. It can still be nonsense. Ask the Twilio simulation for its services and one field is immediately wrong:
{
"services": [
{
"sid": "VAf749B4A7ABEDD59c2020C82e35fEEA56",
"friendly_name": "genuine-callback",
"code_length": 1304189829
}
]
}code_length is a verification code's length. The spec says integer, so the generator produced an integer, and it is 1.3 billion. Every other field here is fine. Your test asserts on this one.
The usual answer at this point is to give up on generation and hand-write the whole API, which is where WireMock started. Instead, write the one response you care about and leave the other 52 alone:
services/
verify/
openapi.yml # the Twilio spec, still serving 52 operations
v2/Services/get/index.json # this one route, answered by hand{
"services": [
{ "sid": "VA0000", "friendly_name": "checkout-otp", "code_length": 6 }
],
"meta": { "page": 0, "page_size": 50 }
}GET /verify/v2/Services now returns exactly that, code_length of 6 and all. The neighbour one path along is untouched and still generated:
$ curl "$BASE/verify/v2/Services/VA0000"
{ "sid": "VAc1C0C7AcAB81C0dFc7E2CE5BFbf079Ad", "friendly_name": "included-notification", ... }This is what makes spec-driven mocking survive a real test suite. You keep the generated 53 and buy back the two that matter, for the price of two files. Add an endpoint to the spec next month and it appears. Your two pinned routes keep answering what you pinned.
None of this exists on the WireMock side, because there is no spec generating the other 52 to override.
How many APIs one mock server holds
WireMock counts mock APIs, and so does its cloud: the free tier stops at three. Mockzilla counts differently, because a simulation is a container rather than a single API. Each API inside it is a service, and a simulation serves as many of them side by side as you give it. The word list is on the terminology page.
So the real ceiling is memory. One simulation on the free plan's 128 MB held this, with every endpoint called at least once:
services/
slack/openapi.yml
notion/openapi.yml
openai/openapi.yml
twitter/openapi.yml
asana/openapi.ymlFive real APIs. 462 operations between them. One URL, with each API under its own prefix, and 80 MB of the 128 used.
More memory is what the paid plans buy, and the simplify command is how you make a large spec fit a small plan.
Mockzilla vs WireMock, feature by feature
| Mockzilla | WireMock | |
|---|---|---|
| Reads an OpenAPI spec | yes | Cloud only |
| Docker image | yes | yes |
| Homebrew | mockzilla | wiremock-standalone |
| Windows and Debian packages | Scoop, apt | jar plus a JVM |
| First-party GitHub Action | yes | no |
| Hosted URL | yes | WireMock Cloud |
| Self-serve paid plans | named plans plus a plan builder | none, free then Enterprise |
| Validates traffic against the spec | requests and responses | no spec to validate against |
| Upstream proxy | yes, with fallback to generated | yes |
| Record and replay real responses | yes, exportable as shared fixtures | yes |
| Importable as a library | Go | Java, .NET, Python, Go, Rust |
| Assert on requests your code sent | no | yes |
| Stateful flows | in the payment and identity sandboxes | yes, in the open source version |
| MCP server for coding agents | yes | Enterprise only |
| License | MIT | Apache 2.0 |
WireMock Cloud's free tier against ours
Both give you 1,000 calls a month. Everything around that number differs.
WireMock Cloud's free tier is three mock APIs, 10 requests a second, one user, and no stateful mocking. Ours is 5 requests a second. Neither number decides anything, because 1,000 requests a month runs out long before throughput does.
Mockzilla's free tier is 5 requests a second and one simulation holding as many APIs as fit. What it does not have is a signup. For API mocking in CI, you add the GitHub Action to a repository and push:
name: mockzilla
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: mockzilla/actions@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}The GITHUB_TOKEN is what proves the repository is yours, and the account is created behind it on that first push. There is no form, no email confirmation and no key to paste anywhere. Your simulation is at https://api.mockz.io/gh/<org>/<repo> when the job finishes. Above the free plan the prices are on the pricing page and you can subscribe yourself.
Scaling past the free tier
WireMock Cloud has two plans. Free, and Enterprise. Nothing in between. The day three mock APIs or 10 requests a second stops being enough, your next move is a sales call, a quote and a contract, whatever the size of the team asking. A two-person startup that needs a fourth mock API joins the same queue as a bank.
Mockzilla has named plans in that gap, priced on the pricing page and subscribed with a card. When none of them fits, you build the plan instead of asking for one. The plan builder exposes the six limits that cost money: monthly requests, throughput, memory, timeout, simulations and PR environments. Move a slider, the price recalculates, you subscribe through checkout and it prorates. Nobody is on the other end of it.
The six move independently because real setups need them that way. A team mocking one enormous spec needs memory and no throughput. A team running parallel CI needs throughput and PR environments against a small spec. On a fixed ladder one of them pays for a number it never uses.
You can still end up talking to someone. Past a certain size the builder stops taking a card and the plan is invoiced. That happens at the top of the self-serve range instead of at the bottom.
What WireMock does better
Three things, and if you need any of them this comparison ends here.
Asserting on the requests your code sent. WireMock does not only answer, it remembers, and it hands that back as a test assertion: verify(getRequestedFor(urlEqualTo("/v2/Services"))) fails the test when the call never happened. Mockzilla records every request in History and you can read it back over the API, but there is no line you drop into a unit test to make it fail. If your tests check outgoing calls rather than what comes back, that is the gap.
Running in-process, in your language. WireMock is a library first in Java and has wrappers for .NET, Python, Go and Rust. Mockzilla is importable too, but only in Go, and the packages are the building blocks rather than a testing API: go get github.com/mockzilla/mockzilla/v2 then factory.NewFactory(spec) gives you a generator you can wire into an httptest.Server in about twenty lines, which is what the servers our codegen mode produces do with the same packages. For a Python or .NET suite that wants a mock inside the test process, WireMock is the one that has it.
Stateful scenarios. WireMock's scenarios move a stub between states, so the same call answers differently the second time, and it is in the free open source version. Mockzilla has nothing that does that for a general API. Our stateful flows are in the payment and identity sandboxes, where each provider's own rules are modelled.
Which WireMock alternative fits your team
Stay on WireMock when the mock lives inside a test suite in a language it has a library for, when you need to assert on the requests your code sent, or when the API has states your tests walk through.
Switch when you already have an OpenAPI document and do not want to maintain a second description of the same API beside it. One file, checked in with the code, deployed by the pipeline you already run, serving every endpoint it describes. Change the spec and the simulation changes. There is no second copy to keep in step.
If the hosted side is what you are weighing, compare the step above free rather than free itself. On WireMock Cloud that step is a sales call. Here it is a plan you configure and pay for yourself.
Install the CLI and point it at a spec you have lying around.