Skip to content

Faults, delays & CORS

Real services are slow sometimes, fail sometimes, and live on another origin than your web app. Mock APIs can do all three on purpose, so you can test timeouts, retries, error handling and CORS before you meet them in production.

Set Delay (ms) in a route’s Behavior section. The route waits this long before it answers; a clock icon marks the route in the list.

  • The delay is at most 24 hours; longer values are cut to that.
  • A client that gives up during the delay ends the wait: nothing is sent, and the traffic log shows the exchange as client left.
  • The delay also comes before the Error (500) and Drop the connection faults, so you can make a route fail slowly.
  • Each request waits on its own: ten requests with a 2-second delay all answer after about 2 seconds.

WebSocket, TCP and UDP reply rules have a Delay ms column. The reply is sent that long after the message arrived. On UDP, at most 1,000 delayed replies may wait at once; more are dropped and logged as Too many delayed replies waiting: this one was dropped.

An event stream server sends its events with the pause set in Interval (ms).

A route’s Fault replaces its normal answer:

FaultIn the fileWhat the client seesTraffic log
NonenoneThe normal answer.
Error (500)error500 Internal Server Error with Content-Type: application/json and {"error": "Injected fault on route <route>"}, where <route> is the route’s name, or its method and path.status 500, note error
Drop the connectionresetThe connection is closed without an answer (after the delay).reset
Never answerhangNothing. The request stays open until the client gives up or the server stops. The delay doesn’t matter.hang, logged right away

How often (%) decides how many requests get the fault: 100 (the default) for every request, 25 for about one in four, picked at random for each request, 0 for none. The route’s row shows a lightning bolt with the fault and its percentage.

Faults apply to routes only. Requests that no route matches get the 404 or the forwarded answer as usual.

GoalRoute setup
A client’s timeoutNever answer, or a Delay longer than the timeout.
RetriesError (500) at 30–50 %, and watch the traffic log for the retries.
Handling of a dropped connectionDrop the connection at 100 %.
A slow, flaky dependencyDelay 2000 plus Error (500) at 20 %.
A specific error body or status (429, 503 with Retry-After)No fault: set the Status, headers and body of a route instead, possibly with conditions.

Browsers block a web page from reading answers from another origin (scheme, host and port) unless the server allows it with CORS headers. A front end on http://localhost:5173 calling a mock on http://127.0.0.1:3000 is such a cross-origin call.

Turn on Allow cross-origin requests (CORS) under Browser access in the mock’s settings. The mock then does two things.

A request with method OPTIONS and an Access-Control-Request-Method header is a browser’s preflight. It is answered before any route is looked at, with 204 No Content and:

HeaderValue
Access-Control-Allow-OriginThe request’s Origin (or * without one)
Access-Control-Allow-Credentialstrue (when there is an Origin)
Access-Control-Allow-MethodsGET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, plus the requested method when it is another one
Access-Control-Allow-HeadersThe headers the browser asked for (Access-Control-Request-Headers), echoed
Access-Control-Allow-Private-Networktrue, when the browser asks (Chrome does before a public site may call a server on your computer)
Access-Control-Max-Age600 (browsers may cache the preflight for 10 minutes)
VaryOrigin (when there is an Origin) and Access-Control-Request-Method, Access-Control-Request-Headers

The log marks these exchanges CORS preflight.

Every answer (from routes, the 404, forwarded answers, faults with status 500, and the 408 and 413 errors) gets:

HeaderValue
Access-Control-Allow-OriginThe request’s Origin, with Access-Control-Allow-Credentials: true and Vary: Origin. Without an Origin header: *.
Access-Control-Expose-HeadersThe names of the answer’s headers (other than Access-Control-*), so your JavaScript can read them.

Echoing the origin with credentials allowed means cookies and Authorization headers work from any origin. When a route sets its own Access-Control-Allow-Origin or Access-Control-Expose-Headers header, the mock keeps the route’s.

With CORS off, the mock adds no CORS headers, and OPTIONS requests go to your routes like any other request. You can then answer CORS yourself with route headers, and a route with method OPTIONS for preflights.

  • The event stream server always sends Access-Control-Allow-Origin: * (enough for EventSource without credentials). It has no CORS switch and answers OPTIONS with 405.
  • WebSocket connections are not subject to CORS. The WebSocket server accepts every Origin.
servers/Flaky API.yaml
name: Flaky API
kind: http
seq: 0
host: 127.0.0.1
port: 3000
http:
cors: true
routes:
- method: GET
path: /orders
status: 200
body: '[]'
delayMs: 1500
fault: error
faultPercent: 25
- method: POST
path: /payments
fault: hang
FieldDefaultDescription
http.routes[].delayMs0Delay before answering, in milliseconds.
http.routes[].faultnonenone, error, reset or hang.
http.routes[].faultPercent100Percentage of requests that get the fault.
http.corsfalseAllow cross-origin requests.