Fake-End: mock APIs with YAML and TypeScript
- My contribution
- Design and implementation.
- Scope
- Local HTTP mocks with file-based routing, interpolation, guards and fixtures.
- Evidence
- Implementation inspected at a2f3290; reconstructed examples are labelled.
Page by Julian Ramirez ·
The interface is ready to send a request. The backend is not ready to answer it. You can hard-code a response inside the component, but that shortcut leaves the request path, loading behavior and failure states largely untested.
Fake-End moves the mock to the HTTP boundary. Local YAML or TypeScript files describe endpoints, letting the frontend keep making requests while the backend contract takes shape. The point is to keep working against an explicit response shape instead of scattering temporary data through the UI.
That becomes especially valuable when the screen has more than a happy path. A useful mock should help you build the empty state, the rejected request and the retry, too.
My contribution and design scope
I built Fake-End to put mock responses at the HTTP boundary. Its implementation connects file-based routes, request interpolation and guarded responses so the frontend can exercise both successful and rejected requests. The constraint is local development: a useful fixture still needs to be reconciled with the real API.
Turn a folder into a small API contract
Fake-End derives routes from the mock file’s location together with its endpoint path. A users.yaml file and a nested api/products.yaml file therefore occupy different places in the local API. The mapping keeps the mock’s structure visible in the project tree.
mock_server/
users.yaml
api/
products.yaml Sources & implementation notes
Inside the file, the method, path, status and body define the response. In this example, the route accepts a user ID and returns it in a successful response. It is enough to connect a frontend request to something the developer can inspect and edit.
- method: GET
path: /:id
status: 200
body:
id: ":id" 200 OK
{ "id": "ada" } TypeScript interfaces offer another route to fixtures. Field names and types can inform generated values, giving the UI data with a useful shape. Those generated examples remain development fixtures; realistic-looking values do not make them production evidence.
Let the request shape the response
A static response is useful until every request starts looking identical. Request interpolation lets the mock reflect a path parameter, a body field or a query value without putting that logic back into the frontend.
Use the controls to follow each value from its request to its response. The syntax differs by source: path parameters use :id, while body and query values use placeholders. Keeping that distinction visible makes mistakes in the mock easier to diagnose.
GET /users/ada id: ":id"
{ "id": "ada" } body: { "name": "Ada" }
name: "{{body.name}}" { "name": "Ada" } GET /users?page=2
page: "{{query.page}}" { "page": "2" } Sources & implementation notes
This is still a contract you control locally. An example response can tell you whether the interface handles a shape; it cannot establish that the eventual backend implements the same behavior. The mock and the real API still need to converge.
Make failure a first-class test case
The next step is to give the endpoint a reason to refuse a request. Fake-End guards evaluate conditions and select a success or failure response. The inspected implementation supports equality, existence and containment checks, including their negative forms.
In the illustrative flow below, an email’s presence determines whether the UI can show a successful creation or needs to ask the user for more information. Both outcomes come from the same endpoint, so the frontend exercises its response handling rather than a separate demo-only branch.
POST /users
{} POST /users
{ "email": "ada@example.com" } Sources & implementation notes
That is the practical payoff: a mock can expose unfinished product behavior before the real service is available. The failure state stops being something to “add later.”
Choose predictability, variation and reload deliberately
Static fixtures help when you want to revisit the same screen state. Dynamic mock functions can be evaluated on each request with --dynamic-mocks, which is useful when variation is part of the test. Dynamic does not mean guaranteed uniqueness, and static generated values need not repeat across server starts.
A → A → A A → B → C Sources & implementation notes
- src/cli-commands/handlers/index.ts · a2f3290
- src/request-processing/endpoint-handler/handlers/processors/dynamic-mock-processor.ts · a2f3290
--dynamic-mocks executes mock functions on each request instead of at startup. Static generated values can differ across server starts; they are not seeded deterministically by this example.
Reloading is also an explicit choice at this revision: run fake-end run --watch. The README describes hot reload broadly, but the implementation enables its watchers only when that flag is set.
I would begin with one endpoint and two meaningful outcomes. Once both work through the real frontend request path, expand the contract. For another example of keeping structure visible before execution, see how Ohtools exposes tool contracts.