Skip to Content
Jumentix DocsGuidesCreate a REST API

Creating REST API with Jumentix

Responsibility in context

  • Owns: HTTP adapter + application use-cases for REST
  • Used with: sdk-rest-client, persistence packages, backend-template app hub
  • Not responsible for: WebSocket/gRPC realtime (see realtime guide) or offline IndexedDB (Cana)

What it is

This guide walks you through bootstrapping, running, and validating a REST service using the Jumentix backend template. You will wire domain logic to an HTTP adapter (Express by default) and call the API from a typed client.

Why it exists

Most junior teams start by editing controller files and hope routes stay aligned with documentation. Jumentix inverts that: OpenAPI is the contract, domain code sits in the center, and the HTTP framework is a replaceable adapter. This guide gives you a repeatable path from env profile → running server → green tests.

Prerequisites

ItemRequiredNotes
Bun 1.3.13+YesSee Getting started
Completed getting-startedRecommendedMental model + Cana playground
Backend template scaffoldYesUse the monorepo apps/backend-template or your internal bootstrap flow
Service Management (optional)For design-first teamsDomain Designer generates entities aligned with OpenAPI

Environment file: apps/backend-template/src/config/.env.dev (or your scaffold’s equivalent).

Glossary

TermMeaning on this page
RESTHTTP API using verbs (GET, POST, …) and JSON payloads.
OpenAPISpec at spec/1.0.0.yml describing paths, schemas, and operationIds.
Runtime profileEnv vars (JUMENTIX_HTTP_FRAMEWORK, JUMENTIX_REALTIME_API) selecting adapters.
ControllerInterface-layer class mapping HTTP requests to use-case calls.
Use caseApplication service implementing one business operation.
Repository portInterface for persistence; implemented by a database adapter.
HTTP adapterExpress/Fastify/etc. module mounting routes from OpenAPI operationIds.
oas:check-routesScript verifying every OpenAPI path resolves to a registered handler.

Numbered steps

Step 1 — Select the REST runtime profile (< 5 minutes)

  1. Open your env file (default: apps/backend-template/src/config/.env.dev).
  2. Set REST-only mode:
JUMENTIX_HTTP_FRAMEWORK=express JUMENTIX_REALTIME_API=no

Supported HTTP frameworks are listed on HTTP adapters.

  1. Start the dev server from the monorepo root:
bun run dev:http

Or from inside apps/backend-template:

bun run dev:rest

Success check: PM2 reports jumentix-dev-http online; curl or browser hits /health (or your scaffold’s health route) with HTTP 200.

Step 2 — Model domain and contracts (< 15 minutes)

  1. Design-first (recommended): open Service Management → Domain Designer. Define entities, relationships, and bounded contexts.
  2. Spec-first: edit OpenAPI at spec/1.0.0.yml — add paths, schemas, and stable operationId values.
  3. Keep request/response DTOs aligned with controller method inputs/outputs.
  4. Shared contract packages (@jumentix/shared-contracts) should mirror the same shapes; see /docs/jumentix/packages/shared-contracts.

Success check: bun run oas:check-routes passes with zero unresolved routes.

Step 3 — Implement the domain flow (< 30 minutes per feature)

Follow the backend template layering — bottom to top:

  1. Domain — entities, value objects, domain events under src/domain/.
  2. Ports — repository and gateway interfaces your use cases depend on.
  3. Use cases — application services orchestrating domain rules.
  4. Controllers — translate HTTP DTOs ↔ use-case inputs/outputs.
  5. Handlers — framework-specific route bindings (Express router modules).

Rule: domain and use cases must not import Express/Fastify. Only adapters do.

Success check: unit tests for the use case pass without starting HTTP.

Step 4 — Bind to the HTTP adapter (< 10 minutes)

  1. Confirm JUMENTIX_HTTP_FRAMEWORK matches the adapter you wired.
  2. REST startup loads start-rest-api.ts (or your scaffold entry) which registers handlers from module interfaces.
  3. Each OpenAPI operationId maps to one controller method via the adapter registry.

Swap adapters by changing env only — domain code stays untouched:

JUMENTIX_HTTP_FRAMEWORK=fastify # example; confirm support on adapters page

Success check: manual request to a new endpoint returns the contract-shaped JSON.

Step 5 — Validate quality gates (< 10 minutes)

Run from monorepo root (or bun --cwd ../.. from backend-template):

bun run lint bun run test:unit bun run oas:check-routes bun run test:integration:express

Optional smoke before pushing:

cd apps/backend-template && bun run test:integration:smoke

Success check: all four commands exit 0; integration test hits real HTTP against the running profile.

Step 6 — Call the API from a client (junior path)

In Node or the browser docs playground, inject the OpenAPI document instead of loading it from disk with fs:

const client = api.createMockClient();
const result = await client.request({ method: 'GET', path: '/health' });
console.log(result.status, result.body);

For production clients, use @jumentix/sdk-rest-client with the same injected spec in browser bundles.

Examples

Static mock client

const client = api.createMockClient();
const result = await client.request({ method: 'GET', path: '/health' });
console.log(result.status, result.body);

Interactive REST client playground

Try the mocked REST client — Run should return a successful /health response:

REST client with mock fetch

Call Task OpenAPI operations with a browser-safe mock client.

const client = api.createMockClient();

const created = await client.request({
  operationId: 'createTask',
  method: 'POST',
  path: '/tasks',
  body: {
    id: 'task-1',
    title: 'Generate REST SDK example',
    categoryId: 'work',
    completed: false
  }
});
const listed = await client.request({
  operationId: 'listTasks',
  method: 'GET',
  path: '/tasks?categoryId=work'
});

return {
  created,
  listed
};

Common errors

SymptomLikely causeFixVerify success
PM2 process exits immediatelyInvalid env file path or missing secretConfirm --env-file=./apps/backend-template/src/config/.env.devbun run dev:http stays online
oas:check-routes failsOpenAPI path has no handlerAdd handler + controller method; rerun checkScript exits 0
404 on documented routeWrong HTTP framework adapter loadedMatch JUMENTIX_HTTP_FRAMEWORK to wired modulecurl returns 200
Integration test timeoutServer not running or wrong portStart dev profile before integration suitetest:integration:express green
Browser client cannot load YAMLfs.readFile in bundleInject parsed OpenAPI object (playground pattern)Mock client works in browser
Domain imports ExpressLayer violationMove HTTP code to adapter/handler layerarch:check-boundaries passes

Junior checklist (“I can …”)

  • Set JUMENTIX_HTTP_FRAMEWORK and JUMENTIX_REALTIME_API=no and start bun run dev:http.
  • Locate spec/1.0.0.yml and explain what an operationId is.
  • Add or trace one path: OpenAPI → controller → use case → repository port.
  • Run bun run oas:check-routes and bun run test:integration:express successfully.
  • Call /health via the sdk-rest-client playground (Run green).
  • Name one HTTP adapter alternative without changing domain code.

Next step

When you need push notifications or live updates, continue to Create a Realtime API. For adapter reference, see HTTP adapters and Errors and responses.