Mockup Simulator
Flip simulate: true in nestia.config.ts and the generated SDK gains a second mode of operation: instead of making HTTP calls, each function answers in-process with a typed random payload.
The point: a frontend can ship UI work before the backend exists. The simulator runs the same input validation the real server would, so bad payloads still fail with the same 400, and good payloads come back with realistic-looking data.
New to this feature? Read Tutorial → Mockup Simulator for the friendly walkthrough. This page is the reference.
Enable
import { INestiaConfig } from "@nestia/sdk";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./src/AppModule";
const config: INestiaConfig = {
input: () => NestFactory.create(AppModule),
output: "src/api",
simulate: true,
};
export default config;Regenerate:
npx nestia sdkEach generated function now has both a real branch (HTTP) and a simulate branch (in-process). Which one runs depends on connection.simulate.
Flip the flag
const connection: api.IConnection = {
host: "http://localhost:37001",
simulate: true,
};
const article = await api.functional.articles.create(connection, {
title: "Hello",
body: "World",
});
// `article` is a fully populated IArticle — generated, not fetched.Behind the scenes the SDK function does roughly:
return connection.simulate
? create.simulate(connection, input) // typia.random<Output> + input validation
: PlainFetcher.fetch(connection, METADATA, input); // real HTTP callBoth branches are typed, so swapping simulate: true ↔ simulate: false is a one-character change.
What the simulator actually does
For each generated function:
- Validate
inputagainst the parameter type (same validator as the real server).- On failure, throw
HttpErrorwith status 400 — exactly what the real server returns.
- On failure, throw
- Generate a
Primitive<Output>value usingtypia.random<Output>(). - Return it.
That means:
- Field-level constraints (
tags.MinLength<3>,tags.Format<"email">) propagate to the random data. Random strings respect minimum lengths; randomFormat<"email">strings look like emails. - Unions and discriminated unions are randomized over their cases.
- Recursive types are bounded automatically.
What it does not do:
- Persist state. Two calls return two independent random values. There is no in-memory database.
- Apply business rules. Authorization, idempotency, rate limits, “you can’t delete what doesn’t exist” — none of that is in the simulator.
Customize per-endpoint
Random data is fine for layout work; for demos and tests you usually want a specific shape. Override the simulate function on any endpoint:
import api from "@my-app/api";
import type { IArticle } from "@my-app/api/lib/structures/IArticle";
api.functional.articles.at.simulate = (connection, id) => ({
id,
title: "Curated demo title",
body: "This article looks real because we wrote it.",
created_at: new Date().toISOString(),
} satisfies IArticle);The simulate function on each SDK namespace has the same signature as the real call. Only override the endpoints that matter for your scenario; the rest stay random.
Production builds
The simulator branch is in the same generated file as the real client. If you set connection.simulate to a statically-known false (or omit it), most bundlers will tree-shake the simulator branch out of the production bundle.
For belt-and-braces — if you want the simulator code physically absent from production — keep two IConnection factories and pick at module load:
export const connection: api.IConnection = process.env.NODE_ENV === "production"
? { host: "https://api.example.com" }
: { host: "http://localhost:37001", simulate: true };See also
- Tutorial → Mockup Simulator — the walkthrough.
- SDK Overview — generator configuration.
- E2E Tests — the generated test suite (which uses real HTTP, not the simulator).