Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Skutopia-org/zod-http-schemas
Uses zod to define well typed API, generate a router that enforces and validates the api at runtime, & generate a well-typed client
https://github.com/Skutopia-org/zod-http-schemas
Last synced: about 2 months ago
JSON representation
Uses zod to define well typed API, generate a router that enforces and validates the api at runtime, & generate a well-typed client
- Host: GitHub
- URL: https://github.com/Skutopia-org/zod-http-schemas
- Owner: Skutopia-org
- License: mit
- Created: 2021-09-12T13:54:28.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-10-01T05:24:29.000Z (3 months ago)
- Last Synced: 2024-10-30T22:25:53.624Z (2 months ago)
- Language: TypeScript
- Size: 1.15 MB
- Stars: 9
- Watchers: 10
- Forks: 2
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-zod - `zod-http-schemas` - Uses zod to define well typed API, generate a router that enforces and validates the api at runtime, & generate a well-typed client. (APIs and Servers)
README
# Zod Http Schemas[![npm monthly downloads](https://img.shields.io/npm/dm/zod-http-schemas.svg?style=flat-square)](https://www.npmjs.com/package/zod-http-schemas) [![current version](https://img.shields.io/npm/v/zod-http-schemas.svg?style=flat-square)](https://www.npmjs.com/package/zod-http-schemas) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
`zod-http-schemas` brings together the best parts of [http-schemas](https://github.com/yortus/http-schemas) and [zod](https://github.com/colinhacks/zod) into one library that:
* Declares the 'shape' of an HTTP API both at compile time and at runtime.
* Supports transformations and refinements.At compile time it statically checks:
* HTTP requests in the client code
* Route handlers in the server code against the declared schema, ensuring usage errors are caught early.At runtime, `zod-http-schemas`:
* validates that response and request payloads match the declared schema
* Trims response payloads of any excess properties, preventing information leaksUse a shared schema for both client and server side code as a single source of truth, ensuring
the client and server always agree on the API.`zod-http-schemas` uses the [`zod`](https://github.com/colinhacks/zod) library for specifying and enforcing schema types.
## Installation
`npm install zod-http-schemas`
## Example Shared Code (use in both client and server)
```ts
import {createHttpSchema} from 'zod-http-schemas';
import * as z from 'zod';// Declare the http schema to be used by both client and server
export const apiSchema = createHttpSchema({
'POST /sum': {
requestBody: z.array(z.number()),
responseBody: z.number(),
},
'GET /greet/:name': {
responseBody: z.string(),
},
});
```## Example Client-Side Code
```ts
import {createHttpClient} from 'zod-http-schemas/client';
import {apiSchema} from '';// Create a strongly-typed http client. These are cheap to create - it's fine to have many of them.
const client = createHttpClient(apiSchema, {baseURL: '/api'});// Some valid request examples
let res1 = client.post('/sum', {body: [1, 2]}); // res1: Promise
let res2 = client.get('/greet/:name', {params: {name: 'Bob'}}); // res2: Promise// Some invalid request examples
let res3 = client.get('/sum', {body: [1, 2]}); // tsc build error & runtime error
let res4 = client.post('/sum', {body: 'foo'}); // tsc build error & runtime error
let res5 = client.post('/blah'); // tsc build error & runtime error
```### Client-side implementation
`zod-http-schemas` uses [Axios](https://github.com/axios/axios) under the hood. Use the same config options with `createHttpClient` as you would with Axios.
_However_ `zod-http-schemas` uses its own default `validateStatus` option that will only reject status codes >= `500`. This lets you include common error responses in your schema, without losing typing.
For example, for a post endpoint you might specify
```typescript
export const apiSchema = createHttpSchema({
'POST /article': {
requestBody: NewArticle,
responseBody: z.union([Article, MyGenericApiErrorType]),
},
});
```Now your clientside code might have a type-guard function that asserts:
```typescript
import {AxiosResponse} from "axios";export const isNotErrorResponse = (
response: AxiosResponse | AxiosResponse
): response is AxiosResponse => {
return response.status < 400;
};
```and used as such:
```typescript
const result = await apiClient.post('/article', {body: {title: 'Hello world'}});
if (isNotErrorResponse(result)) {
// result is AxiosResponse in here
console.log(result.body);
} else {
// Some error occured, so result is typed AxiosResponse
console.error(result.body.myGenericErrorProperty)
}
```## Example Server-Side Code
```ts
import * as express from 'express';
import {createRequestHandler, decorateExpressRouter} from 'http-schemas/server';
import {apiSchema} from '';// Create a strongly-typed express router.
const apiRouter = decorateExpressRouter({schema: apiSchema});// Create a normal express app and mount the strongly-typed router.
const app = express();
app.use(express.json()); // it's a normal express app; mount whatever middleware you want
app.use('/api', apiRouter); // `apiRouter` is just middleware; mount it wherever you want// Add a request handler directly to the router
apiRouter.post('/sum', (req, res) => {
let result = req.body.reduce((sum, n) => sum + n, 0);
res.send(result);
});// Declare a request handler separately, then add it to the router
const greetHandler = createRequestHandler(apiSchema, 'GET', '/greet/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
apiRouter.get('/greet/:name', greetHandler);// Some invalid route handler examples
apiRouter.post('/blah', (req, res) => {/*...*/}); // tsc build error & runtime error
apiRouter.post('/sum', (req, res) => { req.body.foo[0] }); // tsc build error & runtime error
apiRouter.post('/sum', (req, res) => { res.send('foo') }); // tsc build error & runtime errorapp.listen(8000);
```## Full production-like webserver demo
The best way to see `http-schemas` in action is to see it in a real demonstration with documentation. Take a look at [http-schemas-webserver-demo](https://github.com/Antman261/http-schemas-webserver-demo), read the docs, run it and play with it yourself.