Next.js: add one endpoint
Add ContractSpec to an existing Next.js App Router project by wiring a single operation end-to-end with validation and types.
What you'll build
- One OperationSpec with SchemaModel validation.
- A registry wiring the operation to its handler.
- A Next.js route handler that exposes the operation.
1) Install core packages
nextjs-install
bun add -D contractspec
bun add @contractspec/lib.contracts @contractspec/lib.schemaExpected output: added 3 packages and a lockfile update.
2) Define the operation spec
Create src/contracts/healthcheck.operation.ts:
src/contracts/healthcheck.operation.ts
import { defineQuery } from "@contractspec/lib.contracts/operations";
import { SchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
const HealthcheckOutput = new SchemaModel({
name: "HealthcheckOutput",
fields: {
status: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
checkedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
},
});
export const HealthcheckQuery = defineQuery({
meta: {
key: "healthcheck.get",
version: "1.0.0",
description: "Return service health status",
owners: ["@platform.core"],
tags: ["health", "observability"],
},
io: {
input: null,
output: HealthcheckOutput,
},
policy: {
auth: "public",
},
transport: {
rest: { method: "GET" },
gql: { field: "healthcheck_get" },
mcp: { toolName: "healthcheck.get.v1" },
},
});3) Register the operation
Create src/contracts/registry.ts:
src/contracts/registry.ts
import {
OperationSpecRegistry,
installOp,
} from "@contractspec/lib.contracts/operations";
import { HealthcheckQuery } from "./healthcheck.operation";
export const registry = new OperationSpecRegistry();
installOp(registry, HealthcheckQuery, async () => ({
status: "ok",
checkedAt: new Date().toISOString(),
}));4) Add the Next.js handler
Create app/api/ops/[...route]/route.ts:
app/api/ops/[...route]/route.ts
import { makeNextAppHandler } from "@contractspec/lib.contracts/server/rest-next-app";
import { registry } from "@/contracts/registry";
const handler = makeNextAppHandler(registry, async () => ({
actor: "public",
tenantId: "public",
}));
export { handler as GET, handler as POST };Expected output: the route responds at /api/ops/healthcheck.get.
5) Validate the spec
nextjs-validate
contractspec validate src/contracts/healthcheck.operation.tsExpected output: Validation passed.
Example package
Use @contractspec/example.lifecycle-dashboard as a lightweight Next.js snippet reference.
nextjs-example
# Inspect the example docs
contractspec examples show lifecycle-dashboard
# Validate all example manifests in this repo
contractspec examples validate --repo-root .Need team approvals for new endpoints?
Studio adds review gates, shared registries, and audit trails after you ship your first endpoint.
Join Studio waitlist