Skip to content

Commit a10a980

Browse files
committed
Updated to use standard schema
1 parent b6f342d commit a10a980

10 files changed

Lines changed: 497 additions & 684 deletions

File tree

README.md

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,27 @@
22

33
Contract-first, type-safe API definitions for itty-router.
44

5-
`itty-spec` is a small layer on top of itty-router that turns an API contract into:
5+
`itty-spec` is a super lightweight dependency that builds on [itty-router](https://itty.dev/itty-router), [Standard Schema V1](https://github.com/standard-schema/spec), and [Standard Community](https://github.com/standard-community) packages. Designed for small workers, lambdas, and backend servers, it turns an API contract into:
66

77
- A ready-to-export `fetch` handler
88
- Automatic request parsing and validation (params, query, headers, body)
9-
- Fully inferred TypeScript types in your route handlers
9+
- Fully inferred TypeScript types in your route handlers with end-to-end type safety
1010
- Typed, contract-checked responses (status code + content type + body)
11-
- Optional OpenAPI 3.1 spec generation from the same contract (Zod v4 supported)
11+
- Optional OpenAPI 3.1 spec generation and serving from the same contract
1212

13-
If you like itty-router’s “tiny router for Fetch mental model, `itty-spec` keeps that model and adds a single source of truth: the contract.
13+
If you like itty-router's "tiny router for Fetch" mental model, `itty-spec` keeps that model and adds a single source of truth: the contract. Perfect for Cloudflare Workers, AWS Lambda, Node.js servers, Bun, and Deno.
1414

1515
---
1616

1717
## What this project provides
1818

1919
- **Contract-first API design**: define routes, inputs, and outputs once.
20-
- **Runtime validation**: invalid requests are rejected before your handler runs.
21-
- **End-to-end TypeScript inference**: handlers receive typed, validated data.
22-
- **Typed response builder**: responses must match the contract (status/content-type/body).
20+
- **Fully typed TypeScript experience**: complete type inference from contract to handler, with compile-time guarantees for request/response shapes.
21+
- **Runtime validation**: invalid requests are rejected before your handler runs, using Standard Schema V1 compatible validators.
22+
- **End-to-end TypeScript inference**: handlers receive typed, validated data (`validatedParams`, `validatedQuery`, `validatedBody`, `validatedHeaders`).
23+
- **Typed response builder**: responses must match the contract (status/content-type/body) - TypeScript errors catch mismatches at compile time.
2324
- **Fetch-first compatibility**: works in any environment that supports the Fetch API.
24-
- **OpenAPI generation (optional)**: generate an OpenAPI 3.1 document from the contract (currently Zod v4).
25+
- **OpenAPI generation and serving**: generate and serve OpenAPI 3.1 specifications from the same contract using `@standard-community/standard-openapi`.
2526

2627
## What this project is not
2728

@@ -31,6 +32,18 @@ If you like itty-router’s “tiny router for Fetch” mental model, `itty-spec
3132

3233
---
3334

35+
## Foundation
36+
37+
`itty-spec` is built on a lightweight foundation of battle-tested libraries:
38+
39+
- **[itty-router](https://itty.dev/itty-router)** (v5): The tiny router for Fetch that powers routing and request handling.
40+
- **[Standard Schema V1](https://github.com/standard-schema/spec)** (`@standard-schema/spec`): Provides a common interface for schema validation, enabling compatibility with multiple schema libraries.
41+
- **[Standard Community OpenAPI](https://github.com/standard-community/standard-openapi)** (`@standard-community/standard-openapi`): Converts Standard Schema V1 schemas to OpenAPI 3.1 format for documentation and tooling.
42+
43+
This architecture ensures minimal bundle size while providing maximum type safety and developer experience. The library is designed to work seamlessly in edge/serverless environments where every byte counts.
44+
45+
---
46+
3447
## Installation
3548

3649
```bash
@@ -146,6 +159,21 @@ export default {
146159
147160
---
148161
162+
## Target environments
163+
164+
`itty-spec` is designed to be lightweight and efficient, making it ideal for:
165+
166+
- **Cloudflare Workers**: Edge computing with minimal cold start times
167+
- **AWS Lambda**: Serverless functions with size constraints
168+
- **Node.js servers**: Traditional backend servers
169+
- **Bun**: Fast JavaScript runtime
170+
- **Deno**: Secure runtime for JavaScript and TypeScript
171+
- **Any Fetch-compatible environment**: Works wherever the Fetch API is available
172+
173+
The library's minimal dependencies and small bundle size ensure fast startup times and low memory footprint, critical for edge and serverless deployments.
174+
175+
---
176+
149177
## Core concepts
150178
151179
### Contract
@@ -174,32 +202,64 @@ The shape of that response is type-checked against the contract for the current
174202
175203
## Schema support
176204
177-
`itty-spec` is designed to work with schema libraries that implement the Standard Schema V1 interface. In practice:
205+
`itty-spec` uses the [Standard Schema V1](https://github.com/standard-schema/spec) interface, which provides a common abstraction layer for schema validation. This means you can use any Standard Schema V1 compatible library:
206+
207+
* **Zod (v4)**: Fully supported with excellent TypeScript inference and OpenAPI generation. Recommended for the best developer experience.
208+
* **Valibot**: Fully supported with OpenAPI generation via `@standard-community/standard-openapi`.
209+
* **Other Standard Schema compatible libraries**: Can be used for validation; OpenAPI support depends on the library's Standard Schema V1 implementation.
178210
179-
* Zod (v4) is supported and is the best experience today (including OpenAPI generation).
180-
* Other Standard Schema compatible libraries can be used for validation; OpenAPI support may vary.
211+
The Standard Schema V1 interface ensures that your contracts remain portable across different schema libraries while maintaining type safety and runtime validation.
181212
182213
---
183214
184-
## OpenAPI 3.1 generation (optional)
215+
## OpenAPI 3.1 generation and serving (optional)
185216
186-
If you want a formal API spec (documentation, SDK generation, Postman/Insomnia import), generate an OpenAPI document directly from your contract:
217+
Generate an OpenAPI 3.1 specification directly from your contract and serve it as a documentation endpoint:
187218
188219
```ts
189220
import { createOpenApiSpecification } from "itty-spec/openapi";
221+
import { createRouter } from "itty-spec";
190222
import { contract } from "./contract";
223+
import { z } from "zod";
191224
192-
const openApiSpec = createOpenApiSpecification(contract, {
225+
// Generate the OpenAPI spec
226+
const openApiSpec = await createOpenApiSpecification(contract, {
193227
title: "My API",
194228
version: "1.0.0",
195229
description: "Example API built with itty-spec",
196230
servers: [{ url: "https://api.example.com", description: "Production" }],
197231
});
198232
199-
console.log(JSON.stringify(openApiSpec, null, 2));
233+
// Serve it as a route in your router
234+
const router = createRouter({
235+
contract: {
236+
...contract,
237+
getSpec: {
238+
path: "/openapi.json",
239+
method: "GET",
240+
responses: {
241+
200: {
242+
"application/json": { body: z.any() },
243+
},
244+
},
245+
},
246+
},
247+
handlers: {
248+
...yourHandlers,
249+
getSpec: async (request) => {
250+
return request.respond({
251+
status: 200,
252+
contentType: "application/json",
253+
body: openApiSpec,
254+
});
255+
},
256+
},
257+
});
200258
```
201259
202-
OpenAPI generation currently supports Zod v4 schemas via `toJSONSchema()`.
260+
OpenAPI generation uses `@standard-community/standard-openapi` to convert Standard Schema V1 schemas to OpenAPI 3.1 format. This supports Zod v4 and Valibot schemas out of the box. You can then use tools like [Swagger UI](https://swagger.io/tools/swagger-ui/), [Redoc](https://github.com/Redocly/redoc), or [Elements](https://github.com/stoplightio/elements) to render interactive documentation from the served specification.
261+
262+
See the `examples/simple` and `examples/complex` directories for complete examples of serving OpenAPI documentation.
203263
204264
205265
## Repository layout
@@ -210,7 +270,9 @@ OpenAPI generation currently supports Zod v4 schemas via `toJSONSchema()`.
210270
211271
## References
212272
213-
- [itty-router](https://itty.dev/itty-router)
273+
- [itty-router](https://itty.dev/itty-router) - The tiny router for Fetch
274+
- [Standard Schema V1](https://github.com/standard-schema/spec) - Common schema interface
275+
- [Standard Community OpenAPI](https://github.com/standard-community/standard-openapi) - OpenAPI generation from Standard Schema
214276
215277
## License
216278

examples/complex/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { join } from 'path';
1515
/**
1616
* Convert the contract to an OpenAPI specification
1717
*/
18-
const openApiSpecification = createOpenApiSpecification(contract, {
18+
const openApiSpecification = await createOpenApiSpecification(contract, {
1919
title: 'Complex API',
2020
version: '1.0.0',
2121
description: readFileSync(join(import.meta.dirname, 'description.md'), 'utf8'),

examples/simple/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IRequest } from 'itty-router';
1313
/**
1414
* Convert the contract to an OpenAPI specification so we can serve it from the router
1515
*/
16-
const openApiSpecification = createOpenApiSpecification(contract, {
16+
const openApiSpecification = await createOpenApiSpecification(contract, {
1717
title: 'Simple API',
1818
version: '1.0.0',
1919
// markdown description showing of the markdown syntax

examples/valibot/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
/**
1616
* Convert the contract to an OpenAPI specification so we can serve it from the router
1717
*/
18-
const openApiSpecification = createOpenApiSpecification(contract, {
18+
const openApiSpecification = await createOpenApiSpecification(contract, {
1919
title: 'Simple API (Valibot)',
2020
version: '1.0.0',
2121
// markdown description showing of the markdown syntax

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "itty-spec",
3-
"version": "0.2.4",
3+
"version": "0.2.5",
44
"description": "Type-safe contract first itty-router",
55
"type": "module",
66
"main": "./dist/index.cjs",
@@ -69,6 +69,7 @@
6969
"@types/bun": "^1.3.4",
7070
"@types/node": "^25.0.1",
7171
"@valibot/to-json-schema": "^1.5.0",
72+
"zod-openapi": "^4.0.0",
7273
"@vitest/coverage-v8": "^4.0.15",
7374
"@whatwg-node/server": "^0.10.17",
7475
"husky": "^9.1.7",
@@ -81,6 +82,7 @@
8182
"zod": "v4"
8283
},
8384
"dependencies": {
85+
"@standard-community/standard-openapi": "^0.2.0",
8486
"@standard-schema/spec": "^1.0.0",
8587
"itty-router": "^5"
8688
}

pnpm-lock.yaml

Lines changed: 107 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)