{"id":13767286,"url":"https://github.com/Skutopia-org/zod-http-schemas","last_synced_at":"2025-05-10T22:31:42.550Z","repository":{"id":57406405,"uuid":"405655591","full_name":"Skutopia-org/zod-http-schemas","owner":"Skutopia-org","description":"Uses zod to define well typed API, generate a router that enforces and validates the api at runtime, \u0026 generate a well-typed client","archived":false,"fork":false,"pushed_at":"2024-10-01T05:24:29.000Z","size":1202,"stargazers_count":9,"open_issues_count":3,"forks_count":2,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-08T13:16:58.939Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Skutopia-org.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-12T13:54:28.000Z","updated_at":"2024-09-10T12:03:49.000Z","dependencies_parsed_at":"2024-01-07T03:40:15.824Z","dependency_job_id":"f78f452f-6832-4329-a6d2-2ab332e973c2","html_url":"https://github.com/Skutopia-org/zod-http-schemas","commit_stats":null,"previous_names":["antman261/zod-http-schemas"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skutopia-org%2Fzod-http-schemas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skutopia-org%2Fzod-http-schemas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skutopia-org%2Fzod-http-schemas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skutopia-org%2Fzod-http-schemas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Skutopia-org","download_url":"https://codeload.github.com/Skutopia-org/zod-http-schemas/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253492529,"owners_count":21916959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T16:01:07.010Z","updated_at":"2025-05-10T22:31:39.334Z","avatar_url":"https://github.com/Skutopia-org.png","language":"TypeScript","funding_links":[],"categories":["APIs and Servers"],"sub_categories":[],"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/)\n\n`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:\n\n* Declares the 'shape' of an HTTP API both at compile time and at runtime.\n* Supports transformations and refinements.\n\nAt compile time it statically checks:\n\n* HTTP requests in the client code\n* Route handlers in the server code against the declared schema, ensuring usage errors are caught early.\n\nAt runtime, `zod-http-schemas`:\n* validates that response and request payloads match the declared schema\n* Trims response payloads of any excess properties, preventing information leaks\n\nUse a shared schema for both client and server side code as a single source of truth, ensuring\nthe client and server always agree on the API.\n\n`zod-http-schemas` uses the [`zod`](https://github.com/colinhacks/zod) library for specifying and enforcing schema types.\n\n## Installation\n\n`npm install zod-http-schemas`\n\n\n## Example Shared Code (use in both client and server)\n```ts\nimport {createHttpSchema} from 'zod-http-schemas';\nimport * as z from 'zod';\n\n// Declare the http schema to be used by both client and server\nexport const apiSchema = createHttpSchema({\n    'POST /sum': {\n        requestBody: z.array(z.number()),\n        responseBody: z.number(),\n    },\n    'GET /greet/:name': {\n        responseBody: z.string(),\n    },\n});\n```\n\n## Example Client-Side Code\n```ts\nimport {createHttpClient} from 'zod-http-schemas/client';\nimport {apiSchema} from '\u003cpath-to-shared-schema\u003e';\n\n// Create a strongly-typed http client. These are cheap to create - it's fine to have many of them.\nconst client = createHttpClient(apiSchema, {baseURL: '/api'});\n\n// Some valid request examples\nlet res1 = client.post('/sum', {body: [1, 2]});                 // res1: Promise\u003cnumber\u003e\nlet res2 = client.get('/greet/:name', {params: {name: 'Bob'}}); // res2: Promise\u003cstring\u003e\n\n// Some invalid request examples\nlet res3 = client.get('/sum', {body: [1, 2]});                  // tsc build error \u0026 runtime error\nlet res4 = client.post('/sum', {body: 'foo'});                  // tsc build error \u0026 runtime error\nlet res5 = client.post('/blah');                                // tsc build error \u0026 runtime error\n```\n\n### Client-side implementation\n\n`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.\n\n_However_ `zod-http-schemas` uses its own default `validateStatus` option that will only reject status codes \u003e= `500`. This lets you include common error responses in your schema, without losing typing.\n\nFor example, for a post endpoint you might specify\n\n```typescript\nexport const apiSchema = createHttpSchema({\n    'POST /article': {\n        requestBody: NewArticle,\n        responseBody: z.union([Article, MyGenericApiErrorType]),\n    },\n});\n```\n\nNow your clientside code might have a type-guard function that asserts:\n\n```typescript\nimport {AxiosResponse} from \"axios\";\n\nexport const isNotErrorResponse = \u003cT, E\u003e(\n    response: AxiosResponse\u003cT\u003e | AxiosResponse\u003cMyGenericApiErrorType\u003e\n): response is AxiosResponse\u003cT\u003e =\u003e {\n    return response.status \u003c 400;\n};\n```\n\nand used as such:\n\n```typescript\nconst result = await apiClient.post('/article', {body: {title: 'Hello world'}});\nif (isNotErrorResponse(result)) {\n    // result is AxiosResponse\u003cArticle\u003e in here\n    console.log(result.body);\n} else {\n    // Some error occured, so result is typed AxiosResponse\u003cMyGenericApiErrorType\u003e\n    console.error(result.body.myGenericErrorProperty)\n}\n```\n\n## Example Server-Side Code\n```ts\nimport * as express from 'express';\nimport {createRequestHandler, decorateExpressRouter} from 'http-schemas/server';\nimport {apiSchema} from '\u003cpath-to-shared-schema\u003e';\n\n// Create a strongly-typed express router.\nconst apiRouter = decorateExpressRouter({schema: apiSchema});\n\n// Create a normal express app and mount the strongly-typed router.\nconst app = express();\napp.use(express.json()); // it's a normal express app; mount whatever middleware you want\napp.use('/api', apiRouter); // `apiRouter` is just middleware; mount it wherever you want\n\n// Add a request handler directly to the router\napiRouter.post('/sum', (req, res) =\u003e {\n    let result = req.body.reduce((sum, n) =\u003e sum + n, 0);\n    res.send(result);\n});\n\n// Declare a request handler separately, then add it to the router\nconst greetHandler = createRequestHandler(apiSchema, 'GET', '/greet/:name', (req, res) =\u003e {\n    res.send(`Hello, ${req.params.name}!`);\n});\napiRouter.get('/greet/:name', greetHandler);\n\n// Some invalid route handler examples\napiRouter.post('/blah', (req, res) =\u003e {/*...*/});           // tsc build error \u0026 runtime error\napiRouter.post('/sum', (req, res) =\u003e { req.body.foo[0] });  // tsc build error \u0026 runtime error\napiRouter.post('/sum', (req, res) =\u003e { res.send('foo') });  // tsc build error \u0026 runtime error\n\napp.listen(8000);\n```\n\n## Full production-like webserver demo\n\nThe 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSkutopia-org%2Fzod-http-schemas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSkutopia-org%2Fzod-http-schemas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSkutopia-org%2Fzod-http-schemas/lists"}