{"id":15068327,"url":"https://github.com/yishn/ts-route-schema","last_synced_at":"2025-07-19T12:36:28.263Z","repository":{"id":40709045,"uuid":"280455149","full_name":"yishn/ts-route-schema","owner":"yishn","description":"Strictly typed, isomorphic routes.","archived":false,"fork":false,"pushed_at":"2022-12-13T18:36:21.000Z","size":784,"stargazers_count":4,"open_issues_count":12,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-16T09:54:46.886Z","etag":null,"topics":["api","browser","expressjs","fetch","hacktoberfest","isomorphic","routes","server","ts","types","typescript"],"latest_commit_sha":null,"homepage":"https://yishn.github.io/ts-route-schema/","language":"TypeScript","has_issues":false,"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/yishn.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}},"created_at":"2020-07-17T15:07:24.000Z","updated_at":"2024-05-28T12:41:39.000Z","dependencies_parsed_at":"2023-01-28T14:02:09.935Z","dependency_job_id":null,"html_url":"https://github.com/yishn/ts-route-schema","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/yishn/ts-route-schema","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yishn%2Fts-route-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yishn%2Fts-route-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yishn%2Fts-route-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yishn%2Fts-route-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yishn","download_url":"https://codeload.github.com/yishn/ts-route-schema/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yishn%2Fts-route-schema/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265934245,"owners_count":23852092,"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":["api","browser","expressjs","fetch","hacktoberfest","isomorphic","routes","server","ts","types","typescript"],"created_at":"2024-09-25T01:34:04.794Z","updated_at":"2025-07-19T12:36:28.231Z","avatar_url":"https://github.com/yishn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-route-schema\n\n[![CI](https://github.com/yishn/ts-route-schema/workflows/CI/badge.svg?event=push)](https://github.com/yishn/ts-route-schema/actions)\n[![GitHub Repository](https://img.shields.io/badge/-GitHub-%23181717?logo=GitHub)](https://github.com/yishn/ts-route-schema)\n[![Typedoc](https://img.shields.io/badge/-Typedoc-blue?logo=TypeScript)](https://yishn.github.io/ts-route-schema)\n\nStrictly typed, isomorphic routes.\n\n## Introduction\n\nCurrent Node.js server libraries and web frameworks are not very type safe. The\ntype systems are hard to use and also easy to misuse. Furthermore, they are\noften not coupled with frontend code at all, making it easy for frontend code to\nmake incorrect requests to the backend server that could have been avoided by\nthe type compiler in the first place.\n\nThis library helps you write isomorphic code, so your backend routes and\nfrontend HTTP requests can stay in sync. We currently only support the\n[Express](https://expressjs.com) framework.\n\n## Getting Started\n\nWe assume you have an isomorphic TypeScript project set up. For best experience,\noperate in `strict` mode. Install this library using npm:\n\n```\n$ npm install ts-route-schema\n```\n\n### Defining Route Schemas\n\nFirst, we have to define route schemas. These are objects that describes all the\nHTTP methods and route type information that should be made available to both\nbackend and frontend code:\n\n```ts\n// shared/routeSchemas.ts\n\nimport {\n  RouteSchema,\n  MethodSchema,\n  RequestData,\n  ResponseData,\n} from 'ts-route-schema'\n\n/**\n * Creates a greeting for the given name.\n */\nexport const HelloRouteSchema = RouteSchema('/hello/:name', {\n  get: MethodSchema\u003c\n    RequestData\u003c{\n      params: {\n        /**\n         * The name of the person to be greeted.\n         */\n        name: string\n      }\n      query: {\n        /**\n         * The greeting to use.\n         *\n         * @default 'Hello World'\n         */\n        greeting?: string\n      }\n    }\u003e,\n    ResponseData\u003c{\n      body: {\n        /**\n         * The requested greeting.\n         */\n        message: string\n      }\n    }\u003e\n  \u003e(),\n})\n```\n\n### Implementing Routes\n\nOn the backend, you can implement routes based on the previously defined route\nschema:\n\n```ts\n// backend/routes.ts\n\nimport { ExpressRouteImpl } from 'ts-route-schema'\nimport { HelloRouteSchema } from '../shared/routeSchemas'\n\nexport const HelloRoute = ExpressRouteImpl(HelloRouteSchema, {\n  async get(data) {\n    let greeting = data.query.greeting ?? 'Hello World'\n    let message = `${greeting}, ${data.params.name}`\n\n    return {\n      body: {\n        message,\n      },\n    }\n  },\n})\n```\n\nYou can easily mount your route implementation on your Express router:\n\n```ts\n// backend/main.ts\n\nimport * as express from 'express'\nimport { HelloRoute } from './routes'\n\nconst app = express()\n\napp.use(express.json())\nHelloRoute.mountOn(app)\n\napp.listen(3000)\n```\n\n### Requesting Routes\n\nYou can request the route from the frontend as follows:\n\n```ts\n// frontend/fetchGreeting.ts\n\nimport { RouteFetcher } from 'ts-route-schema'\nimport { HelloRouteSchema } from '../shared/routeSchemas'\n\nexport async function fetchGreeting(\n  name: string,\n  greeting: string\n): Promise\u003cstring\u003e {\n  let response = await RouteFetcher(HelloRouteSchema).get({\n    params: { name },\n    query: { greeting },\n  })\n\n  // Equivalent to:\n  //\n  // await fetch(\n  //   `/hello/${encodeURIComponent(name)}?greeting=${encodeURIComponent(\n  //     greeting\n  //   )}`\n  // )\n\n  if (response.status !== 200) {\n    throw new Error('Failed to get greeting')\n  }\n\n  return response.body.message\n}\n```\n\nWe're using [fetch-ponyfill](https://www.npmjs.com/package/fetch-ponyfill) which\nis an isomorphic library, i.e. `RouteFetcher` also works on the backend. On the\nbackend, you might want to set the `pathPrefix` option.\n\n## Building \u0026 Testing\n\nTo run the tests, execute as usual:\n\n```\n$ npm test\n```\n\nTo build the project, use the `build` npm script:\n\n```\n$ npm run build\n```\n\nMake sure you have formatted all files using Prettier beforehand:\n\n```\n$ npm run format\n```\n\nTo build the documentation, execute:\n\n```\n$ npm run docs\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyishn%2Fts-route-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyishn%2Fts-route-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyishn%2Fts-route-schema/lists"}