{"_rev":"7-45bc6b5f5749589a0e9d51ee9c5395cb","time":{"created":"2026-03-15T11:31:10.409Z","modified":"2026-03-15T11:31:10.922Z","0.1.0":"2026-03-15T03:30:30.506Z","0.1.3":"2026-03-15T10:35:06.609Z","0.1.4":"2026-03-15T11:22:21.998Z","0.1.1":"2026-03-15T11:31:10.663Z"},"_id":"@api-typer/core","name":"@api-typer/core","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@api-typer/core","version":"0.1.1","type":"module","description":"Define Express routes with Zod schemas and auto-generate a typed React Query client and OpenAPI spec","author":{"name":"Inas"},"license":"MIT","keywords":["express","zod","openapi","react-query","orval","typescript","codegen","rpc","rest"],"repository":{"type":"git","url":"git+https://github.com/inas-sirhan/api-typer.git"},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsup","typecheck":"tsc --noEmit"},"peerDependencies":{"express":"^5.0.0","zod":"^3.0.0"},"dependencies":{"@asteasolutions/zod-to-openapi":"^7.3.4","orval":"^7.11.2","ts-morph":"^26.0.0"},"devDependencies":{"@orval/core":"^7.11.2","@types/express":"^5.0.2","@types/node":"^22.17.2","express":"^5.1.0","tsup":"^8.5.1","tsx":"^4.20.5","typescript":"^5.9.2","zod":"^3.25.67"},"_id":"@api-typer/core@0.1.1","gitHead":"f571300302afe730a5ec377702595cc6c81e1d8d","bugs":{"url":"https://github.com/inas-sirhan/api-typer/issues"},"homepage":"https://github.com/inas-sirhan/api-typer#readme","_nodeVersion":"22.19.0","_npmVersion":"10.8.3","dist":{"integrity":"sha512-V9+btyOMqzphLUCG50iVgNDC0tjo9c88jCvIE125FEgZX5bzzJrAjVkny/czobm3sduEuCkiy+R2ronBvi6WIQ==","shasum":"906a3d8cc2422a3c555b223ee793a5ec3ea91717","tarball":"https://registry.npmjs.org/@api-typer/core/-/core-0.1.1.tgz","fileCount":9,"unpackedSize":103511,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCpgftUUYu3VL6pbGqZvCsepkdkb1qXuovjtIZ3w9zlhQIhAM5mblcZwKjo6P8Es7dzj+XsDTdg7VUDsGDJWYdZNeOX"}]},"_npmUser":{"name":"inassir","email":"inassirhan@gmail.com"},"directories":{},"maintainers":[{"name":"inassir","email":"inassirhan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_0.1.1_1773574270505_0.08777246351990242"},"_hasShrinkwrap":false}},"maintainers":[{"name":"inassir","email":"inassirhan@gmail.com"}],"description":"Define Express routes with Zod schemas and auto-generate a typed React Query client and OpenAPI spec","homepage":"https://github.com/inas-sirhan/api-typer#readme","keywords":["express","zod","openapi","react-query","orval","typescript","codegen","rpc","rest"],"repository":{"type":"git","url":"git+https://github.com/inas-sirhan/api-typer.git"},"author":{"name":"Inas"},"bugs":{"url":"https://github.com/inas-sirhan/api-typer/issues"},"license":"MIT","readme":"# api-typer\n\n**End-to-end type-safe APIs for Express — with OpenAPI and TanStack Query (React Query) built in.**\n\nDefine your routes once. Get request validation, an OpenAPI spec, and a fully typed TanStack Query client — automatically.\n\n[![npm version](https://img.shields.io/npm/v/@api-typer/core)](https://www.npmjs.com/package/@api-typer/core)\n[![license](https://img.shields.io/npm/l/@api-typer/core)](./LICENSE)\n\n---\n\n## Introduction\n\nBuilding a REST API with Express means writing the route, then the types, then the fetch call, then keeping all three in sync. **api-typer** eliminates that.\n\nYou define an Express route with a Zod schema. api-typer validates every incoming request, generates a standards-compliant OpenAPI spec, and produces a fully typed TanStack Query (React Query) client — complete with hooks, direct calls, and cache helpers.\n\nYour route definition *is* the contract. No separate package. No code duplication. No drift.\n\n---\n\n## Highlights\n\n- 🔗 **End-to-end type safety** — inputs, outputs, and errors are fully typed from server to client\n- ⚡ **TanStack Query (React Query) client** — typed hooks, direct calls, and cache helpers generated automatically\n- 📘 **First-class OpenAPI** — generates a standards-compliant OpenAPI 3.0 spec from your route definitions\n- ✅ **Automatic validation** — Zod schemas validated on every request, `422` with structured errors on failure\n- 🛟 **Type-safe responses** — `respond('ok', data)` is typed to the exact schema you defined\n- 🌿 **Express-native** — drop into any existing Express app, no new framework to learn\n- 🚦 **Route conflict detection** — throws at startup if a route would be shadowed by another\n- 🔌 **Zero frontend coupling** — the generated client has no runtime dependency on api-typer\n- 👀 **Examples** — check out the [`examples/`](./examples) folder to get started quickly\n\n---\n\n## Try it out\n\nClone the repo and run the example:\n\n```bash\ngit clone https://github.com/inas-sirhan/api-typer.git\ncd api-typer\nnpm install\nnpx tsx examples/basic.ts\n```\n\nThis generates `artifacts/openapi.json` and `artifacts/api.ts` from the example routes.\n\n---\n\n## Install in your project\n\n```bash\nnpm install @api-typer/core\n```\n\n> More documentation coming soon.\n\n---\n\n## Quick start\n\n### 1. Define routes\n\n```ts\nimport express from 'express';\nimport * as z from 'zod';\nimport { createApiBuilder, createSuccessResponse, createErrorResponse } from '@api-typer/core';\n\nconst app = express();\napp.use(express.json());\n\nconst { route, sync } = createApiBuilder(app);\n\nroute(\n    {\n        operationId: 'get-user',\n        method: 'get',\n        path: '/users/:id',\n        summary: 'Get a user by ID',\n        tags: ['users'],\n        request: z.object({ id: z.string() }),\n        responses: {\n            ok: createSuccessResponse({\n                statusCode: 200,\n                schema: z.object({ id: z.string(), name: z.string() }),\n            }),\n            notFound: createErrorResponse({\n                statusCode: 404,\n                errorCode: 'USER_NOT_FOUND',\n            }),\n        },\n    },\n    async ({ input, respond, req, res }) => {\n        // input, respond — typed to your schema\n        // req, res — raw Express objects, available when you need them\n        const user = await db.findUser(input.id);\n        if (!user) return respond('notFound');\n        respond('ok', user);\n    },\n);\n\nawait sync({ serverUrl: 'http://localhost:3000' });\n\napp.listen(3000);\n```\n\n### 2. What gets generated\n\nOutputs to `./artifacts/`:\n\n| File | Description |\n|------|-------------|\n| `openapi.json` | OpenAPI 3.0 spec |\n| `api.ts` | Typed React Query hooks + `Api` namespace |\n| `axios.ts` | Pre-configured Axios instance (generated once, yours to edit — add interceptors, etc.) |\n\n### 3. Use in React\n\n```ts\nimport { Api, useGetGetUserQueryData, useSetGetUserQueryData } from './artifacts/api';\n\n// Params, response data, and errors are all fully typed\nconst { data: user, error } = Api.useGetUser({ id: '123' });\n\n// Cache read — typed to the exact response schema\nconst getUserData = useGetGetUserQueryData();\ngetUserData({ id: '123' });\n\n// Cache write — updater is typed, wrong shape is a compile error\nconst setUserData = useSetGetUserQueryData();\nsetUserData({ id: '123' }, updatedUser);\n```\n\nIf you rename a route or change its request or response shape, TypeScript will surface every broken call in your frontend.\n\n---\n\n## How it works\n\n```\nroute()\n  │\n  ├─▶  Express handler  (Zod validation on every request)\n  │\n  └─▶  sync()\n         │\n         ├─▶  openapi.json  (OpenAPI 3.0 spec)\n         │\n         └─▶  api.ts  (React Query hooks via Orval)\n                │\n                └─▶  Api.useGetUser(...)\n                     Api.createUser(...)\n                     Api.deleteUser(...)\n```\n\n---\n\n## API Reference\n\n### `createApiBuilder(app, options?)`\n\n| Option | Type | Default |\n|--------|------|---------|\n| `prefix` | `string` | `'/api'` |\n\nReturns `{ route, sync }`.\n\n---\n\n### `route(config, handler)`\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `operationId` | `string` | Unique kebab-case ID (e.g. `'get-user'`) |\n| `method` | `'get' \\| 'post' \\| 'put' \\| 'patch' \\| 'delete'` | HTTP method |\n| `path` | `string` | Express path (e.g. `'/users/:id'`) |\n| `request` | `ZodObject` | Schema for path params + body/query |\n| `responses` | `Record<string, ResponseDef>` | Keyed response definitions |\n| `middlewares?` | `RequestHandler[]` | Express middlewares to run before the handler |\n| `summary?` | `string` | OpenAPI summary |\n| `description?` | `string` | OpenAPI description |\n| `tags?` | `string[]` | OpenAPI tags |\n\n---\n\n### `sync(options?)`\n\n| Option | Type | Default |\n|--------|------|---------|\n| `openApiOutput` | `string` | `'./artifacts'` |\n| `clientOutput` | `string` | `'./artifacts'` |\n| `serverUrl` | `string` | `'http://localhost:3000'` |\n\n---\n\n### Response helpers\n\n```ts\n// Success with a response body\ncreateSuccessResponse({ statusCode, schema, description? })\n\n// Error with a standard { errorCode: string } body\ncreateErrorResponse({ statusCode, errorCode, description? })\n\n// 204 No Content\ncreateSuccessResponseNoContent({ description? })\n```\n\n---\n\n## License\n\nMIT\n\n---\n\nv0.1.3 — early release. A more robust and feature-rich version will be released soon — stay tuned.\n","readmeFilename":"README.md"}