DEV Community

Cover image for When One API Means Different Mocks for Each Team - Designing a Distributed WireMock Setup
ykagano
ykagano

Posted on • Edited on

When One API Means Different Mocks for Each Team - Designing a Distributed WireMock Setup

I'm ykagano, a backend engineer working on payment systems.
After running WireMock for an extended period, I found that managing consistent mock behavior across environments became surprisingly difficult as our systems and teams grew. In this article, I'll share the tool I built to solve this problem and the design decisions behind it.


Where Single-Instance WireMock Hits Its Limits

Running a single WireMock instance is straightforward. POST JSON to /__admin/mappings to register stubs, reset when testing is done. Simple.

But things change when you run into situations like these.

Scaling out for load testing.

When you place multiple WireMock instances behind a load balancer, you need to distribute the same stubs to all of them. You might think, "Why not share stub JSON files via Docker volumes?" That does solve file distribution, but WireMock doesn't automatically detect file changes. To pick up changes, you need to restart each instance or call the Admin API to reload. With N instances, that's N operations — and you'll end up writing a script to automate it.

Multiple teams sharing the same API mock but expecting different behavior.

Consider a payment API mock: Team A wants to test primarily with success responses, while Team B needs to focus on timeouts and error cases. When sharing a single WireMock instance, stub overwrites become a constant battle.

The learning curve for creating and editing stub definitions.

WireMock stubs are written in JSON, and getting URL pattern matching and response structures right requires reading through the documentation. Not everyone on the team can write these JSON definitions fluently, so stub creation and maintenance tends to fall on a few specific members.


Existing Options and Their Limitations

I evaluated the existing options for this problem.

WireMock Cloud is a commercial SaaS with distributed management and a GUI. It's close to ideal in terms of features, but we couldn't adopt it due to the inability to self-host, cost concerns, and internal security policy constraints.

Writing custom scripts to call the Admin API works, but for building a continuous load testing environment, I wanted to minimize cognitive load on non-essential tasks like stub synchronization. Ideally, you shouldn't even need to remember how to run a script — one-click sync from a GUI is the goal.

Git-managed JSON files with CI/CD pipelines looks elegant on paper, but it doesn't fit the "tweak a stub and test it immediately" development cycle. Running commit → push → CI → deploy every time is too heavy during the trial-and-error phase of load testing.

Based on these considerations, I concluded that we needed a self-hosted tool with a GUI that provides instant deployment and centralized management of distributed instances, and decided to build WireMock Hub.


Design Decision 1: Why "Project" Is the Top-Level Concept

The most important design decision in WireMock Hub was placing the project at the top of the data model.

Projects

Project
├── Instance (WireMock instance): 1..N
└── Stub Mapping: 0..N
Enter fullscreen mode Exit fullscreen mode

In most mock management tools, the instance is the top-level concept — "this instance contains these stubs."

However, in our environment, multiple teams needed different mock behaviors for the same API. Team A needed a payment API mock returning success responses, Team B needed one that simulated timeouts and server errors. Each team had ended up building their own mock applications.

By making the project the top-level concept, the following becomes possible.

Managing multiple behaviors for the same API in parallel.

You can create separate projects like "Payment API - Success Testing" and "Payment API - Error Testing," each linked to different sets of instances.

Switching environments becomes switching projects.

Environment separation like dev / staging / load-test can be expressed as projects. Just change the instance URLs linked to each project to deploy the same stub set to different environments.

Cross-team interference is structurally eliminated.

Since projects are isolated, one team's stub changes never affect another team's environment.


Design Decision 2: Why Full Reset + Redeploy

WireMock Hub's sync process uses a full reset followed by a complete redeploy approach.

Instances

Sync flow:
1. Execute DELETE /__admin/mappings on all instances (reset)
2. POST all stubs from SQLite to /__admin/mappings on all instances
Enter fullscreen mode Exit fullscreen mode

You might think, "Wouldn't differential sync be more efficient?" I considered it, but chose the full reset approach for the following reasons.

WireMock's Admin API doesn't guarantee a reliable view of the current stub state.

If someone manually adds stubs via the API or changes come from another tool, the state Hub knows about and the actual instance state will diverge. Differential sync breaks down when this assumption fails.

An unknown state is the most dangerous state.

In load testing, the assumption is that mock responses match expectations. Running with "the state is probably correct" under differential sync undermines the reliability of test results.

The cost of a full reset is acceptable.

With a few hundred stubs, a full delete and re-register takes only seconds. Since stub deployment isn't a frequent operation, this brief wait is not an issue.

This is a trade-off between correctness and efficiency, and in a mock environment, correctness should take priority.


Design Decision 3: Why No External Database

The choice of SQLite as the data store was driven by the principle of minimizing the barrier to adoption.

WireMock itself is a tool that sells on "start with a single docker run." If its management tool requires setting up PostgreSQL or MySQL, the adoption barrier becomes too high.

With SQLite, no external database setup is needed. Data is persisted simply by mounting a Docker Volume, backups are just file copies, and sharing data between teams is as easy as sharing the SQLite file.

# This is all you need for persistence
services:
  wiremock-hub:
    image: ghcr.io/ykagano/wiremock-hub:latest
    ports:
      - "80:80"
    volumes:
      - wiremock-hub-data:/data
Enter fullscreen mode Exit fullscreen mode

Of course, at large scale (thousands of stubs, dozens of teams using it simultaneously), SQLite's concurrent write performance could become a bottleneck. But for a WireMock management tool, write frequency isn't that high, making it a sufficient choice for now.


WireMock Hub Overview

Here's the architecture of WireMock Hub, reflecting the design decisions above.

┌────────────────────────────────────────────────────────────┐
│                        WireMock Hub                        │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐  │
│  │   Frontend   │ -> │   Backend    │ -> │    SQLite    │  │
│  │   (Vue 3)    │    │  (Fastify)   │    │ (Persistence)│  │
│  └──────────────┘    └──────────────┘    └──────────────┘  │
└────────────────────────────────────────────────────────────┘
                              │
                              │ Sync (Full Reset + Redeploy)
                              ▼
         ┌────────────────────┼────────────────────┐
         │                    │                    │
         ▼                    ▼                    ▼
   ┌──────────┐         ┌──────────┐         ┌──────────┐
   │ WireMock │         │ WireMock │         │ WireMock │
   │ Instance │         │ Instance │         │ Instance │
   │    #1    │         │    #2    │         │    #3    │
   └──────────┘         └──────────┘         └──────────┘
Enter fullscreen mode Exit fullscreen mode

Key features:

One-click sync:

Deploy stubs to all instances linked to a project with a single click. A full reset precedes deployment, ensuring no state inconsistencies.

Test requests:

Send requests directly from the GUI to verify stub behavior. The entire cycle of creating a stub → syncing → verifying can be completed in the browser.

Stub generation from request logs:

Convert actual requests sent to WireMock into stubs with one click, significantly reducing the effort of writing JSON by hand.


Quick Start

The Fastest Way to Try It (All-in-One Image)

An image bundling both WireMock Hub and WireMock is available.

docker run -d -p 3000:3000 yukagano/wiremock-hub:latest
open http://localhost:3000/hub/
Enter fullscreen mode Exit fullscreen mode

After starting, create a project and register http://localhost:8080 as a WireMock instance to start exploring all the features.


One Tool for Both Daily Development and Load Testing

The design decision to make projects the top-level concept also enables different use cases to coexist within a single tool.

For day-to-day development, keep the all-in-one image running as a single instance and use it as a mock server with your development project's stubs. Instead of Postman or curl, you can create, test, and verify stubs entirely from the browser.

Meanwhile, the multiple WireMock instances for load testing don't need to run all the time. Spin them up only when running load tests, sync the load testing project's stubs to all instances at once, and shut them down when done.

The ability to handle these two fundamentally different use cases — everyday mocking and load test mocking — simply by switching projects is a direct benefit of placing projects at the top of the design.

GitHub: https://github.com/ykagano/wiremock-hub
Documentation: https://ykagano.github.io/wiremock-hub/

Feedback and issues are very welcome!

Top comments (2)

Collapse
 
leeturner profile image
Lee Turner • Edited

Hey, I'm an engineer working on the WireMock team. Thanks for this great write up! It is awesome to see someone building around WireMock open source and really adding value to the community.

I just wanted to let you know, in case you come around to evaluating WireMock Cloud again, that we have a number of options for self hosting. We have the Runner which allows you to run your mocks in your environments and if you need a fully air gapped solution, you can run WireMock Cloud on-prem.

Again, thanks for the article.

Collapse
 
ykagano profile image
ykagano

Hi Lee, nice to meet you.
Thank you for your comment and all your great work on WireMock.

I appreciate you letting me know about WireMock Runner and WireMock Cloud.
WireMock Hub was created as a mini version of WireMock Cloud for a very specific use case, and it already works well enough for my needs.

Thanks again!