@routepact/core
v0.1.13
Published
Type-safe route spec definitions shared between server and client
Downloads
1,714
Readme
@routepact/core
Shared types and utilities for defining type-safe route pacts. This package is the contract between your server and client - import it in shared code that both sides depend on.
Installation
npm install @routepact/coreYou also need a schema library that implements the Standard Schema interface (e.g. Zod, Valibot, ArkType). Examples below use Zod but any Standard Schema-compatible library works.
npm install zod # or valibot, arktype, etc.Defining a pact
A pact describes a single endpoint: its path, HTTP method, and optional validation schemas for the request body, response body, query parameters, path parameters, and response metadata. Schemas must implement the Standard Schema interface.
Use definePact to get full type inference while keeping literal types (exact path strings, method literals):
import { z } from "zod";
import { definePact } from "@routepact/core";
export const PostPacts = {
list: definePact({
method: "get",
path: "/posts",
response: z.object({
items: z.object({ id: z.string(), title: z.string() }).array(),
total: z.number(),
page: z.number(),
}),
query: z.object({
page: z.string().optional(),
limit: z.string().optional(),
}),
}),
getById: definePact({
method: "get",
path: "/posts/:id",
response: z.object({
id: z.string(),
title: z.string(),
body: z.string(),
}),
}),
create: definePact({
method: "post",
path: "/posts",
request: z.object({ title: z.string(), body: z.string() }),
response: z.object({
id: z.string(),
title: z.string(),
body: z.string(),
}),
}),
update: definePact({
method: "patch",
path: "/posts/:id",
request: z.object({
title: z.string().optional(),
body: z.string().optional(),
}),
response: z.object({
id: z.string(),
title: z.string(),
body: z.string(),
}),
}),
delete: definePact({
method: "delete",
path: "/posts/:id",
}),
};Validation schemas
| Field | Required for | Description |
| ---------- | ------------------------------- | ----------------------------------------------------------------- |
| request | Only for post, patch, put | Object schema for req.body on the server |
| response | Optional | Object schema for the full response body sent via res.json(...) |
| query | Optional | Object schema for query parameters - typed on both server and client |
All validation schemas must describe object types (e.g. z.object(...) in Zod) - routepact is opinionated that request bodies, responses, and query parameters are always objects. Primitive or array schemas are not supported at the pact level.
Path parameters
Parameters in the path (:param) are extracted as a type-safe object. If a path contains :id, the params option is required and typed as { id: string }.
// TypeScript requires params when the path has parameters
await request(PostPacts.getById, { params: { id: "abc" } });
// TypeScript forbids params when there are none
await request(PostPacts.list);On the server, ctx.params is automatically populated from the URL and typed as { [key: string]: string } based on the path string - no Zod schema needed.
Query parameters
Add a query schema to make query parameters type-safe on both server and client. If any field in the schema is required, TypeScript will require the query option at the call site:
const list = definePact({
method: "get",
path: "/posts",
query: z.object({ page: z.string().optional(), sort: z.string() }), // sort is required
});
// TypeScript requires query.sort
await request(list, { query: { sort: "createdAt" } });Type reference
| Type | Description |
| ----------------------------- | ------------------------------------------------------------------------------------------------- |
| RoutePact | Generic type for a single pact definition |
| AnyRoutePact | Widened pact type - used internally and in package integrations |
| AnyRouteValidation | The set of optional Standard Schema-compatible schemas that can be attached to a pact |
| HttpMethod | "get" \| "post" \| "patch" \| "put" \| "delete" |
| RouteOptions<TPact> | Inferred call-site options (params, payload, query) for a pact |
| RouteOptionsRequired<TPact> | true if options are required (pact has params or a request schema) |
| QueryOption<TPact> | Inferred query option - required if the query schema has required fields |
| PactRequest<TPact> | Inferred output type of the request body - never if the pact has no request schema |
| PactInputRequest<TPact> | Inferred input type of the request body (before transforms) - never if no request schema |
| PactParams<TPact> | Inferred path parameter record - never if the path has no :param segments |
| PactQuery<TPact> | Inferred output type of query parameters - never if the pact has no query schema |
| PactInputQuery<TPact> | Inferred input type of query parameters (before transforms) - never if no query schema |
| PactResponse<TPact> | Inferred response type - the schema's output type when a response schema is defined, never otherwise |
| ExtractParams<TPath> | Extracts parameter names from a path string |
| ExpectedParams<TPath> | Maps extracted param names to string values |
