{"id":16321579,"url":"https://github.com/joselion/ts-routeways","last_synced_at":"2025-10-05T18:35:57.356Z","repository":{"id":38845826,"uuid":"490539420","full_name":"JoseLion/ts-routeways","owner":"JoseLion","description":"A type-safe solution to define and consume routes","archived":false,"fork":false,"pushed_at":"2024-11-20T10:43:27.000Z","size":7559,"stargazers_count":6,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-19T07:22:51.502Z","etag":null,"topics":["codecs","hacktoberfest","hacktoberfest2022","query-params","querystring","react","router","routes","routeways","routing","type-safe","typesafe","typesafety","typescript"],"latest_commit_sha":null,"homepage":"https://joselion.github.io/ts-routeways/","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/JoseLion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null},"funding":{"github":"JoseLion"}},"created_at":"2022-05-10T04:19:33.000Z","updated_at":"2024-07-23T05:18:16.000Z","dependencies_parsed_at":"2023-11-20T06:29:56.047Z","dependency_job_id":"77de2e67-b75d-4422-b16b-9c1a0ce2e1ee","html_url":"https://github.com/JoseLion/ts-routeways","commit_stats":{"total_commits":62,"total_committers":1,"mean_commits":62.0,"dds":0.0,"last_synced_commit":"0208e737d536009c8f92df87f937ca9e333c3692"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/JoseLion/ts-routeways","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoseLion%2Fts-routeways","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoseLion%2Fts-routeways/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoseLion%2Fts-routeways/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoseLion%2Fts-routeways/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JoseLion","download_url":"https://codeload.github.com/JoseLion/ts-routeways/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JoseLion%2Fts-routeways/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265999094,"owners_count":23862219,"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":["codecs","hacktoberfest","hacktoberfest2022","query-params","querystring","react","router","routes","routeways","routing","type-safe","typesafe","typesafety","typescript"],"created_at":"2024-10-10T22:48:15.398Z","updated_at":"2025-10-05T18:35:52.297Z","avatar_url":"https://github.com/JoseLion.png","language":"TypeScript","funding_links":["https://github.com/sponsors/JoseLion"],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/JoseLion/ts-routeways/actions/workflows/ci.yml/badge.svg)](https://github.com/JoseLion/ts-routeways/actions/workflows/ci.yml)\r\n[![CodeQL](https://github.com/JoseLion/ts-routeways/actions/workflows/codeql.yml/badge.svg)](https://github.com/JoseLion/ts-routeways/actions/workflows/codeql.yml)\r\n[![Pages](https://github.com/JoseLion/ts-routeways/actions/workflows/pages.yml/badge.svg)](https://github.com/JoseLion/ts-routeways/actions/workflows/pages.yml)\r\n[![Release](https://github.com/JoseLion/ts-routeways/actions/workflows/release.yml/badge.svg)](https://github.com/JoseLion/ts-routeways/actions/workflows/release.yml)\r\n[![NPM version](https://img.shields.io/npm/v/ts-routeways?logo=npm)](https://www.npmjs.com/package/ts-routeways)\r\n[![NPM bundle size](https://img.shields.io/bundlephobia/min/ts-routeways)](https://www.npmjs.com/package/ts-routeways)\r\n[![NPM downloads](https://img.shields.io/npm/dm/ts-routeways)](https://www.npmjs.com/package/ts-routeways)\r\n[![NPM license](https://img.shields.io/npm/l/ts-routeways)](https://github.com/JoseLion/ts-routeways/blob/main/LICENSE)\r\n[![GitHub Release Date](https://img.shields.io/github/release-date/JoseLion/ts-routeways)](https://github.com/JoseLion/ts-routeways/releases)\r\n[![Known Vulnerabilities](https://snyk.io/test/github/JoseLion/ts-routeways/badge.svg)](https://snyk.io/test/github/JoseLion/ts-routeways)\r\n\r\n![Logo](./docs/assets/logo%40128x128.png)\r\n\r\n\u003e Lightweight and type-safe! All-in-one solution to define and consume routes\r\n\r\n# ts-routeways\r\n\r\n## Why?\r\n\r\n\"Yet another route library?\" you might think. In part you're right, there are a lot of libraries out there designed to create routes, some of them routes are plain, some do allow nesting; some of them have simple-wide types like `any`, and some of them have full type-safety and inference through template literals. However, the reality is that none give you the complete solution.\r\n\r\nThat is to say, once you have some routes defined, you need to consume them! You want to create URLs from them, taking into account path variables and query parameters, and as well parse a URL into an object, so you can safely use the variables and parameters in the current route. Typically, you'd use a separate library to handle query parameters, and maybe another to parse/build URLs. Wouldn't it be nice if you'd have \"one ring to rule them all\"? With `ts-routeways` now you can!\r\n\r\nSome features of `ts-routeways` include:\r\n\r\n🪶 Lightweight implementation. Zero extra dependencies.\r\n\r\n✅ TypeScript optimized. Static check ensures routes are parsed/built as they should be.\r\n\r\n🍰 Simple API. Allows nesting and splitting into multiple files (useful on bigger apps).\r\n\r\n⚙️ Codec based. Parameters are defined with codecs imagination is the limit.\r\n\u003e We provide the most commmon codecs in on single `Codecs` object, which can be extended to add custom codecs of your own.\r\n\r\n🔧 Fully agnostic. You can use it with any framework/library, the concepts apply to any web-like router.\r\n\r\n## Install\r\n\r\nWith NPM:\r\n\r\n```bash\r\nnpm i ts-routeways\r\n```\r\n\r\nWith Yarn:\r\n\r\n```bash\r\nyarn add ts-routeways\r\n```\r\n\r\n## Usage\r\n\r\nThe concept is simple, use the builder to create a `Routeways` instance that contains your custom routes. Then use that instance to access your routes in the same structured way you define them. Each route can make a raw string URL, or parse a URL to consume the parameters on it.\r\n\r\n```ts\r\nimport { Codecs, Routeways } from \"ts-routeways\";\r\n\r\nexport const MainRoutes = Routeways()\r\n  .path({ name: \"home\", path: \"/home\" }) // (1)\r\n  .nest({\r\n    name: \"users\",\r\n    path: \"/users\",\r\n    subRoutes: Routeways() // (2)\r\n      .path({ name: \"view\", path: \"/view/:userId\", pathVars: { userId: Codecs.Number } }) // (3)\r\n      .path({ name \"search\", path: \"/search\", queryParams: { byName: Codecs.String, showAll: Codecs.Boolean } }) // (4)\r\n  })\r\n  .build(); // (5)\r\n```\r\n\r\n\u003e **(1)** Nothing else required, no path variables in the path.\r\n\u003e \u003cbr/\u003e\r\n\u003e **(2)** On `.nest(..)` the `subRoutes` property is required.\r\n\u003e \u003cbr/\u003e\r\n\u003e **(3)** A path variable is present in the path (`:userId`). Now `pathVars` is required and it must contain a `userId` property with the codec you prefer.\r\n\u003e \u003cbr/\u003e\r\n\u003e **(4)** The `queryParams` property is optional. Use it to define the query parameters the route supports and the codecs to be used on each one. By definition, query parameters are optional in any URL.\r\n\u003e \u003cbr/\u003e\r\n\u003e **(5)** Finally, build an instance of your own `Routeways` to use it.\r\n\r\nWith your `Routeways` defined, you can use them like in the examples below:\r\n\r\n```ts\r\nimport { MainRoutes } from \"./MainRoutes\";\r\n\r\nMainRoutes.home.makeUrl(); // -\u003e /home\r\nMainRoutes.users.makeUrl(); // -\u003e /users\r\n\r\nMainRoutes.users.view.makeUrl({ userId: 3 }); // -\u003e /users/view/3\r\nMainRoutes.users.search.makeUrl(); // -\u003e /users/search (query params are always optional)\r\nMainRoutes.users.search.makeUrl({ byName: \"foo\", showAll: true }); // -\u003e /users/search?byName=foo\u0026showAll=true\r\n\r\nconst {\r\n  pathVars: {\r\n    userId, // 3 (number)\r\n  },\r\n} = MainRoutes.users.view.parseUrl(\"/users/view/3\");\r\n\r\nconst {\r\n  pathVars: {\r\n    byName, // john (string)\r\n  },\r\n  queryParams: {\r\n    showAll, // false (boolean)\r\n  },\r\n} = MainRoutes.users.search.parseUrl(\"/users/search?byName=john\u0026showAll=false\")\r\n\r\n// #template: useful for 3rd party routing libraries\r\nMainRoutes.home.template(); // -\u003e /home\r\nMainRoutes.users.view.template(); // -\u003e /users/view/:userId\r\n```\r\n\r\n## Custom Codecs\r\n\r\nOnly the most basic data types are provided by the `Codecs` helper. Sometimes you'll find yourself in need of a more complex codec, some specific data type, or a serializable class instance. With `ts-routeways`, you can use custom codecs, and also use its extension mechanism for the `Codecs` helper, so you can have all your codecs in one place. You need only to create an object containing a `decode` and an `encode` method:\r\n```ts\r\ninterface Codec\u003cT\u003e {\r\n  decode(text: string): T;\r\n  encode(value: T): string;\r\n}\r\n```\r\n\r\nOptionally, add your codec to the `Codecs` helper. Also, extend the `CodecsType` interface to add the types:\r\n```ts\r\ndeclare module \"ts-routeways\" {\r\n\r\n  export interface CodecsType {\r\n    UUID: Codec\u003cUUID\u003e;\r\n  }\r\n}\r\n\r\nconst UUIDCodec = { /* ... */ };\r\n\r\naddCodec(\"UUID\", UUIDCodec);\r\n\r\nCodecs.UUID // Ready to use on a router\r\n```\r\n\r\nYou can find more details and a complete example of custom codecs in the link below:\r\n\r\n[Custom Codecs ⚙️](./docs/CustomCodecs.md)\r\n\r\n## Getting your QueryParam types back\r\n\r\nSometimes you'd like to use the queryParam types that are already defined in your router somewhere else. For instance, in the argument of the function in charge of making a request with those query parameters. This could be a very common pattern, let's assume we have `MainRoutes` as presented in the [Usage section](#usage) and an API that receives `byName` and `showAll` query params.\r\n\r\n**Not so safe, isn't it?**\r\n```ts\r\nexport function searchUsers(params: any): Promise\u003cUser[]\u003e {\r\n//                                  ^ What am I supposed to use here?\r\n  return axios.get\u003cUser[]\u003e(\"/api/users\", { params })\r\n    .then(({ data }) =\u003e data);\r\n}\r\n```\r\n\r\nInstead, you can infer the type of the query params of any route using the types helper `InferQueryParams\u003cR\u003e`, where `R` is the type of your route:\r\n\r\n**This is better!**\r\n```ts\r\nimport { InferQueryParams } from \"ts-routeways\";\r\n\r\ntype UsersQueryParams = InferQueryParams\u003ctypeof MainRoutes.users.search\u003e;\r\n//   ^ type = { byName?: string; showAll?: boolean; }\r\n\r\nexport function searchUsers(params: UsersQueryParams): Promise\u003cUser[]\u003e {\r\n  return axios.get\u003cUser[]\u003e(\"/api/users\", { params })\r\n    .then(({ data }) =\u003e data);\r\n}\r\n```\r\n\r\n## Working with React.js ⚛️\r\n\r\nIf you are looking to use ts-routeways with React.js, please refer to [react-routeways](https://www.npmjs.com/package/react-routeways) instead. This package seamlessly integrates ts-routeways with React.js and [react-router](https://reactrouter.com/).\r\n\r\n## API Reference\r\n\r\nThe library is documented on its JSDocs, which is the most useful place for help. However, if you'd like to see the API reference, you can find them in the link below:\r\n\r\n[API Reference 📚](./docs/APIReference.md)\r\n\r\n## Something's missing?\r\n\r\nSuggestions are always welcome! Please create an [issue](https://github.com/JoseLion/ts-routeways/issues/new) describing the request, feature, or bug. We'll try to look into it as soon as possible 🙂\r\n\r\n## Contributions\r\n\r\nContributions are very welcome! To do so, please fork this repository and open a Pull Request to the `main` branch.\r\n\r\n## License\r\n\r\n[MIT License](./LICENSE)\r\n\r\n---\r\n\r\n_Attribution:_ \u003ca href=\"https://www.flaticon.com/free-icons/route\" title=\"route icons\"\u003eRoute icon created by Smashicons - Flaticon\u003c/a\u003e\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoselion%2Fts-routeways","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoselion%2Fts-routeways","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoselion%2Fts-routeways/lists"}