{"id":16331152,"url":"https://github.com/steelydylan/next-zod-router","last_synced_at":"2025-03-20T23:30:18.494Z","repository":{"id":152479661,"uuid":"625728922","full_name":"steelydylan/next-zod-router","owner":"steelydylan","description":"Zod driven simple method routing for Next.js","archived":false,"fork":false,"pushed_at":"2024-07-19T12:49:34.000Z","size":774,"stargazers_count":40,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"development","last_synced_at":"2025-03-17T16:55:29.979Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/steelydylan.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2023-04-10T01:18:58.000Z","updated_at":"2025-03-07T08:16:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"d009805a-c68c-4e73-bb69-45de9800ba36","html_url":"https://github.com/steelydylan/next-zod-router","commit_stats":null,"previous_names":["steelydylan/next-zod-router"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steelydylan%2Fnext-zod-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steelydylan%2Fnext-zod-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steelydylan%2Fnext-zod-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steelydylan%2Fnext-zod-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steelydylan","download_url":"https://codeload.github.com/steelydylan/next-zod-router/tar.gz/refs/heads/development","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244710183,"owners_count":20497210,"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-10-10T23:25:50.355Z","updated_at":"2025-03-20T23:30:18.488Z","avatar_url":"https://github.com/steelydylan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# next-zod-router\n\nA library for simple API routing in Next.js\nwhile leveraging Zod and Typescript to create typesafe routes and middlewares with built in validation.\n\n![](./screenshot.png)\n\n## Motivation\n\nI wanted to create type-safe APIs in Next.js using zod and also wanted to generate type definition files for client-side use so that I could use intuitive API calls.\nBut I couldn't find a library that met my needs, so I created this library.\n\n## Features\n\n- Type-safe API routing\n- Type-safe API call\n- Validation using zod\n- Error handling\n- Type definition file generation for client-side use\n- Middleware support\n\n## Demo\n\nhttps://stackblitz.com/edit/next-typescript-32qrbx?embed=1\u0026file=pages/index.tsx\u0026file=pages/api/sample/[id].ts\u0026hideNavigation=1\u0026view=editor\n\n## Usage\n\n### Installation\n\n\n```bash\n## npm\nnpm install next-zod-router\n\n## yarn\nyarn add next-zod-router\n```\n\n### Server-side\n\n1. Use zod to define the types for body, query, and res.\n2. Create routing handling with createRouter.\n3. Assign types to the created routing handling with validate.\n4. Export the types as GetHandler and PostHandler.\n\n```ts\n// pages/api/sample.ts\nimport { ApiHandler, createRouter, validate } from \"next-zod-router\";\nimport { z } from \"zod\";\n\n/* Schema definition using zod */\nconst postValidation = {\n  body: z.object({\n    foo: z.string(),\n  }),\n  query: z.object({\n    bar: z.string().optional(),\n  }),\n  res: z.object({\n    message: z.string(),\n  }),\n}\n\nconst getValidation = {\n  query: z.object({\n    bar: z.string().optional(),\n  }),\n  res: z.object({\n    message: z.string(),\n  }),\n}    \n\n/* Routing */\nconst router = createRouter()\n\nrouter\n  .use((req, res, next) =\u003e {\n    console.log(\"middleware\");\n    return next()\n  })\n  .post(\n    validate(postValidation),\n    (req, res) =\u003e {\n      req.body.foo;\n      req.query.bar;\n      res.status(200).json({ message: \"ok\" });\n    })\n  .get(\n    validate(getValidation),\n    (req, res) =\u003e {\n      req.query.bar;\n      res.status(200).json({ message: \"ok\" });\n    })\n\n/* Type export */\n// the export type name should be as follows\n// so that the type definition file can be generated correctly via the command.\nexport type PostHandler = ApiHandler\u003ctypeof postValidation\u003e\nexport type GetHandler = ApiHandler\u003ctypeof getValidation\u003e\n\n/* Routing handling export */\nexport default router.run()\n```\n\n### Type generation\n\n\n```bash\n## npm\nnpx next-zod-router\n\n## yarn\nyarn next-zod-router\n```\n\nAdding a script to your package.json is convenient.\n\n```json\n{\n  \"scripts\": {\n    \"apigen\": \"next-zod-router\"\n  }\n}\n```\n\n```bash\nnpm run apigen\n```\n\n### Client-side\n\n```ts\nimport { client } from \"next-zod-router\";\n\n// Type-safe API call\nconst { data, error } = await client.post(\"/api/sample\", {\n  query: {\n    bar: \"baz\",\n  },\n  body: {\n    foo: \"bar\",\n  },\n})\n```\n\n\n### dynamic routing\n\n#### Server-side\n\n```ts\n// pages/api/[id].ts\n\nconst getValidation = {\n  // 👇 for server side validation\n  // 👇 also necessary for client side url construction\n  query: z.object({\n    id: z.string().optional(),\n  }),\n}\n\nrouter\n  .get(\n    validate(getValidation),\n    (req, res) =\u003e {\n      req.query.id;\n      res.status(200).json({ message: \"ok\" });\n    })\n```\n\n#### Client-side\n\n```ts\n// client.ts\nimport { client } from \"next-zod-router\";\n\nclient.get(\"/api/[id]\", {\n  query: {\n    id: \"1\",\n  },\n})\n\n// url will be /api/1\n```\n\n\n\n### Error handling\n\n\n#### throw error\n\n```ts\n// pages/api/sample.ts\nrouter\n  .post(\n    validate(postValidation),\n    (req, res) =\u003e {\n      const session = getSession(req)\n      if (!session) {\n        throw createError(401, \"Unauthorized\")\n      }\n      res.status(200).json({ message: \"ok\" });\n    })\n```\n\n#### custom error handling\n\n```ts\n// pages/api/sample.ts\n\nrouter\n  .onError((err, req, res) =\u003e {\n    // custom error handling\n    res.status(err.statusCode).json({ message: err.message });\n  })\n```\n\n### Middleware\n\nexpress-like middleware is supported.\n\n```ts\n// pages/api/sample.ts\nimport cors from \"cors\";\nimport { createRouter, validate } from \"next-zod-router\";\nimport { z } from \"zod\";\n\nconst postValidation = {\n  res: z.object({\n    message: z.string(),\n  }),\n}\n\nrouter\n  .use(cors())\n  .post(\n    validate(postValidation),\n    (req, res) =\u003e {\n      res.status(200).json({ message: \"ok\" });\n    })\n```\n\n\n## Command options\n\nThe default pages directory is `pages`, so if you want to change it, you can use the `--pagesDir` option.\n\n```bash\nnext-zod-router --pagesDir=src/pages\n```\n\n| Option | Description | Default value |\n| --- | --- | --- |\n| --pagesDir | Pages directory | pages |\n| --baseDir | Project directory | . |\n| --distDir | Type definition file output destination\t | node_modules/.next-zod-router |\n| --moduleNameSpace | Type definition file module name | .next-zod-router |\n| --watch | Watch mode | false |\n\n## Tips\n\n### Add session property to Request type\n\nIf you want to add session property to Request type, you can use the following code.\n\n```ts\n// global.d.ts\nimport { IncomingMessage } from \"http\";\n\ndeclare module 'next' {\n  export interface NextApiRequest extends IncomingMessage {\n    session: Session\n  }\n}\n```\n\n### Next.js development\n\nWhen developing with Next.js, you can use the following code to generate type definition files automatically.\n\n```json\n{\n  \"scripts\": {\n    \"dev\": \"npm-run-all -p dev:*\",\n    \"dev:next\": \"next dev\",\n    \"dev:apigen\": \"next-zod-router -w\"\n  }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteelydylan%2Fnext-zod-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteelydylan%2Fnext-zod-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteelydylan%2Fnext-zod-router/lists"}