Skip to content

Commit c0ddf86

Browse files
README updates
1 parent 89bef58 commit c0ddf86

File tree

3 files changed

+48
-42
lines changed

3 files changed

+48
-42
lines changed

README.md

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
`openapi-typescript-server` is a CLI and minimal runtime library that helps you implement type-safe APIs documented by OpenAPI.
44

5-
It works by generating a TypeScript server interface based on the operations defined in your OpenAPI spec using types from the [openapi-typescript](https://github.com/openapi-ts/openapi-typescript) package.
5+
It works by generating a TypeScript server interface based on your OpenAPI spec using types from [openapi-typescript](https://github.com/openapi-ts/openapi-typescript).
66

7-
You provide a concrete implementation that satisfies the interface.
7+
You provide a concrete implementation that satisfies the interface for each path operation.
88

9-
At runtime, your implementation is handed off to adapters that convert it into HTTP handlers for various frameworks like [Express](https://expressjs.com/).
9+
At runtime, your implementation is converted into HTTP handlers for various frameworks like [Express](./packages/openapi-typescript-server-express/README.md).
1010

1111
## Stability
1212

@@ -18,13 +18,13 @@ For now, proceed with caution!
1818

1919
### Installation
2020

21-
Install the build-time packages as dev dependencies:
21+
Install build-time packages as dev dependencies:
2222

2323
```bash
2424
npm install -D openapi-typescript openapi-typescript-server
2525
```
2626

27-
Install the runtime adapter (Express example):
27+
Install runtime adapter (Express example):
2828

2929
```bash
3030
npm install openapi-typescript-server-express
@@ -36,7 +36,7 @@ npm install openapi-typescript-server-express
3636
npm install express-openapi-validator
3737
```
3838

39-
### Basic Example
39+
### Quickstart
4040

4141
Given an OpenAPI spec like this:
4242

@@ -95,23 +95,25 @@ Generate types from your OpenAPI spec:
9595
npx openapi-typescript ./spec.yaml --output ./gen/schema.d.ts
9696
```
9797

98-
Generate the server interface
98+
Generate the server interface:
9999

100100
```bash
101101
npx openapi-typescript-server ./spec.yaml --types ./schema.d.ts --output ./gen/server.ts
102102
```
103103

104104
> **Note**: The `--types` path is relative to the output directory so the generated code can import it correctly.
105105
106-
Implement your API handlers
106+
Implement your API handlers:
107107

108108
`api.ts`
109109

110110
```typescript
111111
import type * as ServerTypes from "./gen/server.ts";
112112
import type { Request, Response } from "express";
113113

114-
// Explicitly specifying the type rather than relying on structural typing, gives you type inference for handler arguments and faster feedback in the definition vs at the call site.
114+
// Explicitly specifying the type (rather than relying on structural typing)
115+
// gives you type inference for handler arguments and faster feedback in the
116+
// definition vs at the call site.
115117
const API: ServerTypes.Server<Request, Response> = {
116118
makePetSpeak: async ({ parameters, requestBody }) => {
117119
const petId = parameters.path.petId;
@@ -162,7 +164,7 @@ export default function makeApp() {
162164
// Register your typed route handlers
163165
const routeHandlers = registerRouteHandlers(API);
164166

165-
// Make Express routes from your route handlers.
167+
// Make Express routes from your route handlers
166168
registerRoutes(routeHandlers, apiRouter);
167169

168170
// Mount to the correct base path
@@ -282,7 +284,35 @@ Satisfy the compiler to get it working again:
282284

283285
This pattern also guides you when adding or removing routes.
284286

285-
### How does this work?
287+
## Deeper dive
288+
289+
### Design goals
290+
291+
The main goal of this package is to ensure that the server implementation stays in sync with the API documentation by generating a typed interface _from_ the OpenAPI spec.
292+
293+
This schema-first approach documents your system for humans or LLM coding agents, and helps you achieve type safety across the system.
294+
295+
### In scope/goals
296+
297+
- **Trade off build time complexity for runtime simplicity**. By using codegen as a build step, the surface area of what's executed on the server is reduced.
298+
- **Keep package footprint small**. Keep the solution space narrow by integrating with existing solutions.
299+
300+
### Out of scope/non-goals
301+
302+
- **Schema validation & type coercion**. This package assumes that all data inputs have been validated and coerced to the expected types by the time they get to your route handlers. Use other middleware like [express-openapi-validator](https://github.com/cdimascio/express-openapi-validator) to handle validation and coercion.
303+
- **Security & auth scopes**. This package does not handle any authentication nor authorization and ignores all security aspects of your OpenAPI schema.
304+
305+
### Inspiration & prior art
306+
307+
This package was heavily influenced by the [Go oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) package and gRPC ergonomics.
308+
309+
### Comparison to other solutions
310+
311+
- [openapi-typescript](https://github.com/openapi-ts/openapi-typescript). This library only generates types from an OpenAPI spec, not operation interfaces. This is foundational to this library, but only part of the solution.
312+
- [openapi-ts-router](https://github.com/builder-group/community/tree/develop/packages/openapi-ts-router). This library works similarly, but requires that you bring your own path validators alongside the route handlers. It also doesn't ensure that you've implemented the entire spec.
313+
- [tRPC](https://trpc.io/). This library tightly couples frontend and backend code and only works for systems that are TypeScript on the frontend and backend. It also requires a decent amount of runtime complexity to tie clients and servers together.
314+
315+
### How does it work?
286316

287317
#### Route handling
288318

@@ -301,15 +331,15 @@ The return value is enveloped in `content` so that you can provide `headers` and
301331

302332
> **Note**: These return values are a bit verbose, but, since the HTTP handling is delegated to the adapters, they have the added benefit of being easily testable functions with data in and out.
303333
304-
Your route handlers are packaged up into the generated `registerRouteHandlers` function. This returns a list of objects containing the route method, path, and handler function.
334+
Your route handlers are packaged up into the generated `registerRouteHandlers` function which returns a list of objects containing the route method, path, and handler function.
305335

306-
Adapters supply a `registerRoutes` function which iterates through this data structure and uses the underlying framework (i.e. Express) to add each route, set headers, serialize response bodies, and terminate the response.
336+
Adapters supply a `registerRoutes` function. It iterates through this data structure and uses the underlying framework (i.e. Express) to add each route, set headers, serialize response bodies, and terminate the response.
307337

308338
#### Content type serialization
309339

310340
Content type serialization and deserialization happens in the adapter layer.
311341

312-
For Express, request bodies can be deserialized to JavaScript objects by middleware. The Express adapter assumes this has already happened and passes the deserialized (and presumably validated and coerced) JavaScript objects to your route handlers. The content type is passed as an argument to your handler in case you need to return a different response shape per content type.
342+
For Express, request bodies can be deserialized to JavaScript objects by middleware. The Express adapter assumes this has already happened and passes the deserialized (and presumably validated and coerced) JavaScript objects to your route handlers. The content type is passed as an argument to your handler in case you need to return a different response shape per.
313343

314344
For response body serialization, `application/json` is built in and happens automatically. Other content types can be handled by supplying a `serializers` option to the `registerRoutes` function with custom serialization functions keyed by content type.
315345

@@ -426,29 +456,3 @@ export default API;
426456
```
427457

428458
Otherwise, thrown errors will propagate up the call stack to your global error handler. You can check for `err instanceof NotImplementedError` if you want to handle those with a `501 Not Implemented` status code.
429-
430-
## Design goals
431-
432-
The main goal of this package is to ensure that the server implementation stays in sync with the API documentation by generating a typed interface _from_ the OpenAPI spec.
433-
434-
This schema-first approach documents your system for humans or LLM coding agents, and helps you achieve type safety across the system.
435-
436-
### In scope/goals
437-
438-
- **Trade off build time complexity for runtime simplicity**. By using codegen as a build step, the surface area of what's executed on the server is reduced.
439-
- **Keep package footprint small**. Keep the solution space narrow by integrating with existing solutions.
440-
441-
### Out of scope/non-goals
442-
443-
- **Schema validation & type coercion**. This package assumes that all data inputs have been validated and coerced to the expected types by the time they get to your route handlers. Use other middleware like [express-openapi-validator](https://github.com/cdimascio/express-openapi-validator) to handle validation and coercion.
444-
- **Security & auth scopes**. This package does not handle any authentication nor authorization and ignores all security aspects of your OpenAPI schema.
445-
446-
### Inspiration & prior art
447-
448-
This package was heavily influenced by the [Go oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) package and gRPC ergonomics.
449-
450-
### Comparison to other solutions
451-
452-
- [openapi-typescript](https://github.com/openapi-ts/openapi-typescript). This library only generates types from an OpenAPI spec, not operation interfaces. This is foundational to this library, but only part of the solution.
453-
- [openapi-ts-router](https://github.com/builder-group/community/tree/develop/packages/openapi-ts-router). This library works similarly, but requires that you bring your own path validators alongside the route handlers. It also doesn't ensure that you've implemented the entire spec.
454-
- [tRPC](https://trpc.io/). This library tightly couples frontend and backend code and only works for systems that are TypeScript on the frontend and backend. It also requires a decent amount of runtime complexity to tie clients and servers together.

examples/docs/api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type * as ServerTypes from "./gen/server.ts";
22
import type { Request, Response } from "express";
33

4-
// Explicitly specifying the type rather than relying on structural typing, gives you type inference for handler arguments and faster feedback in the definition vs at the call site.
4+
// Explicitly specifying the type (rather than relying on structural typing)
5+
// gives you type inference for handler arguments and faster feedback in the
6+
// definition vs at the call site.
57
const API: ServerTypes.Server<Request, Response> = {
68
makePetSpeak: async ({ parameters, requestBody }) => {
79
const petId = parameters.path.petId;

examples/docs/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function makeApp() {
2323
// Register your typed route handlers
2424
const routeHandlers = registerRouteHandlers(API);
2525

26-
// Make Express routes from your route handlers.
26+
// Make Express routes from your route handlers
2727
registerRoutes(routeHandlers, apiRouter);
2828

2929
// Mount to the correct base path

0 commit comments

Comments
 (0)