← All guides

A Karate mock server alternative for when the mock should just be a URL

Credit where due: Karate is one of the most loved test-automation frameworks there is β€” API tests, mocks, performance, and even UI automation unified behind one readable DSL, ~9k GitHub stars, MIT-licensed core, and very much alive: v2.1.2 shipped August 14, 2026, with commits landing the day we wrote this. Its built-in mock server is a genuinely clever idea β€” the same feature-file syntax you test with also authors the mock, which makes consumer-driven contracts feel natural. And unlike several tools we've put through this drill, the basics genuinely work: we ran v2.1.2 (one 12 MB fatjar, java -jar karate.jar mock -m mock.feature -p 8080), and in-session state was real (our POST persisted and a later GET returned it), responseDelay = 2000 measured a true 2.0 s, hot-reload via -W is built in, and an entirely unmatched path returns a clean 404 {"error":"no matching scenario"}. If your job is testing services with Karate and stubbing their dependencies in the same repo and idiom, keep doing exactly that.

This page is about a different job that Karate mocks get pressed into: a data-shaped sandbox API for a frontend, a prototype, or a teammate β€” the "just give me /products that behaves like a real backend" job. We wrote a 25-line CRUD feature file per their docs and put it through the same drill we use on every tool. It works β€” and it has walls.

The walls (each one verified on v2.1.2, August 2026)

Wall 1: every data behavior is code you author, scenario by scenario. A Karate mock is a program: Background: holds your state map, and each route is a Scenario: pathMatches('/products') && methodIs('post') block whose body you write in embedded JavaScript. Our feature file handled list/get/create/delete in ~25 lines β€” genuinely compact β€” but that's where the free lunch ends. GET /products?category=kitchen&limit=1 returned the entire collection, category ignored, limit ignored: query semantics exist only if you write a paramValue() branch for every param, on every resource. Filtering, sorting, pagination, search, relations β€” each one is more mock code for you to maintain and debug.

Wall 2: the 200-empty-body trap is one undefined variable away. In our matched pathMatches('/products/{id}') scenario, an unknown id made response undefined β€” and the server answered HTTP 200 with an empty body. res.json() throws, and your frontend's error handling never sees the 404 it was written for. (Fully unmatched paths do 404 cleanly in v2 β€” credit β€” but the ids-that-don't-exist case lives inside your matched scenario, where correctness is on you.)

Wall 3: it's in-memory β€” a restart loses everything. We POSTed a record, killed the JVM, started it again: the record was gone and the seed data was back. State lives exactly as long as one process. Fine for a test run that spawns the mock; fatal for a mock a team hits for a week.

Wall 4: there is no hosted option β€” the mock is a local JVM process. The fatjar needs a Java runtime installed, and the server runs on your machine. The moment a teammate, a phone on another network, a CI job against a deployed preview, or a workshop room needs to hit the mock, you're deploying and babysitting infrastructure yourself. (The core is free and MIT β€” Karate Labs monetizes IDE plugins and enterprise protocol add-ons, not hosting; there's no mock-hosting cloud to pay for even if you wanted one.)

The 60-second switch

Where you'd author a feature file and run a jar, create a hosted project instead β€” nothing to run, nothing to keep alive, no Java required:

curl -X POST https://mockbird.mockbird.workers.dev/api/projects \
  -H 'content-type: application/json' -d '{"name":"my-api","preset":"ecommerce"}'
# β†’ {"id":"<PID>","adminKey":"…","baseUrl":"https://mockbird.mockbird.workers.dev/m/<PID>",…}
# 4 resources, realistic seeded records, live at a public URL immediately

Your Background: seed map has a direct equivalent: import a db.json β€” {"products":[…your exact records…]} β€” and your records are hosted verbatim, ids preserved. Then every query behavior from Wall 1 is just true, with zero scenarios authored:

# the params our feature file ignored (ran on the shared demo before publishing):
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?sortBy=price&order=desc&limit=2&select=name,price'
# β†’ the two most expensive products, only the fields you asked for

curl 'https://mockbird.mockbird.workers.dev/m/demo/products?inStock=true&limit=2&page=2'
# β†’ filtered AND paginated

# writes persist β€” and survive every restart we don't have:
curl -X POST https://mockbird.mockbird.workers.dev/m/demo/products \
  -H 'content-type: application/json' -d '{"name":"my product","price":9.99}'
# β†’ {"name":"my product","price":9.99,"id":31}
curl https://mockbird.mockbird.workers.dev/m/demo/products/31   # β†’ same record, tomorrow too
# and a missing record is an honest 404 β€” not a 200 with an empty body

Karate mock concepts β†’ Mockbird

Karate mockMockbirdNotes
java -jar karate.jar mock -m mock.feature -p 8080POST /api/projectshosted URL instead of a JVM on localhost; nothing to operate, no Java
Background: state map + seeddb.json importrecords hosted verbatim, ids preserved; or typed fakes via presets + ?seed=N
one Scenario: per method+pathgenerated REST endpointslist/get/create/patch/delete on every resource, plus nested routes and relations
hand-coded paramValue() branchesalways-on query toolkitfilter, _gte/_lte/_ne/_like, sort, pagination, search, ?select= β€” zero authoring
responseDelay = 2000?mock_delay=2000honest: theirs works (we measured it) β€” ours needs no scenario, any endpoint, per request
authored error scenarios?mock_status=503, ?mock_seq=500,500,200, ?mock_chaos=0.3failure drills as query params β€” verified 503 + 500,500,200 on the demo
in-memory state, wiped on restartpersistent storage by defaultdeliberate resets via snapshots; pin per request with X-Mockbird-Snapshot
fixed routes like /healthcustom routes + templating{{params}}, {{now}}, {{body.x}} β€” no JS to maintain
inspecting karate.logrequest inspectorlast 50 requests with headers + bodies, in the dashboard
the feature file is the specgenerated OpenAPI, Postman, TS typesexported from the live schema at /m/<PID>/openapi.json etc.
Karate tests (the main event)keep thempoint them at the hosted URL β€” see below

Use both β€” they compose

Karate the test framework and Mockbird solve different problems, and they work great together: your existing Karate tests run unchanged against a hosted project β€” no mock feature file, no process to spawn in CI, and the same URL your frontend and your teammate's phone are already using:

Feature: products API

Background:
  * url 'https://mockbird.mockbird.workers.dev/m/<PID>'

Scenario: create then read back
  Given path 'products'
  And request { name: 'Spot check', price: 12.5 }
  When method post
  Then status 201
  * def id = response.id
  Given path 'products', id
  When method get
  Then status 200
  And match response.name == 'Spot check'

Keep Karate mocks where they shine: contract-style stubs that live next to the Karate tests that consume them, in infrastructure you already run.

Try it in 10 seconds (shared demo, no setup)

# everything our feature file would have needed hand-written branches for:
curl 'https://mockbird.mockbird.workers.dev/m/demo/products?page=2&limit=3'

# failure and latency simulation without authoring a scenario:
curl -i 'https://mockbird.mockbird.workers.dev/m/demo/products?mock_status=503'
curl 'https://mockbird.mockbird.workers.dev/m/demo/products/1?mock_delay=2000'

# create your own β€” one click, no terminal:
# https://mockbird.mockbird.workers.dev/app#new=ecommerce

Honest comparison

Karate mock serverMockbird
Pricefree, MIT corefree while in beta
Hosted URL others can hitno β€” local JVM process; self-deploy to shareyes β€” 10,000 requests/project/day, no signup
Stateful CRUDyes, if you code it β€” in-memory, wiped on restart (verified)yes β€” persistent database, snapshots, restore
Pagination/filter/sort/search on listsonly what you hand-code per param, per resourcealways on, every resource
Missing-record behavior200 + empty body unless you code the 404 (verified)honest 404, always
Latency / failure simulationresponseDelay works (verified); failures = authored scenariosmock_delay/mock_status/mock_seq/mock_chaos query params
Arbitrary logic in the mockfull embedded JS β€” anything you can writetemplated custom routes only β€” theirs is stronger
Same-idiom tests + mocksyes β€” the whole point, and it's lovelyno DSL; tests hit a URL
Generated OpenAPI/Postman/types of the mocknoyes β€” all three, from the live schema
GraphQLauthorable by handgenerated endpoint β€” queries, mutations, relations
Works offline / no request capsyesno
Install footprint12 MB fatjar + a Java runtimezero β€” it's a URL
Maintenancevery active β€” v2.1.2 Aug 2026actively developed

Written by the Mockbird maker β€” bias disclosed. Where Karate genuinely wins: the unified test-automation DSL (API, mocks, performance, UI) is unique and excellent; mocks-as-consumer-driven-contracts next to the tests that consume them; full JavaScript programmability inside the mock; hot-reload; offline use with no request caps; clean 404s on unmatched paths; and working responseDelay β€” all free and MIT at the core. Every behavioral claim above was verified by us on August 26, 2026 against Karate v2.1.2 (official release fatjar, karate mock subcommand): the CRUD feature file, ignored query params, 200-empty on missing ids inside a matched scenario, the restart wipe, the 404 on unmatched paths, and the 2.0 s measured delay were all observed directly. If any of this changes, we'll update the page.

Full API reference in the docs. More guides: stubby4j alternative Β· MockServer alternative Β· WireMock Cloud alternative Β· mountebank alternative Β· Hoverfly alternative Β· Prism alternative Β· free mock API tools compared. Create your API β†’