Skip to content

t8js/url-shape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

npm Lightweight TypeScript ✓ browser ✓ node ✓

url-shape

Type-safe schema-based URL builder

Installation: npm i url-shape

Creating a URL schema with Zod or Yup

import { createURLSchema } from "url-shape";
import { z } from "zod";

export const { url, match, validate } = createURLSchema({
  "/": null, // goes without parameters
  "/sections/:id": {
    params: z.object({
      id: z.coerce.number(),
    }),
  },
  "/search": {
    query: z.object({
      term: z.string(),
      view: z.optional(z.enum(["full", "compact"])),
    }),
  },
});

With Zod, remember to use the .coerce part in the schema for non-string parameters so that string URL components are converted to the preferred types.

Using a URL schema

Use the functions returned from createURLSchema() to build, match, and validate URLs in a type-safe manner. A type-aware code editor will highlight typos in the URLs and type mismatches in their parameters.

url("/sections/:id", { params: { id: 10 } }).href // "/sections/10"
url("/sections/:id", { params: { id: 10 } }).toString() // "/sections/10"
String(url("/sections/:id", { params: { id: 10 } })) // "/sections/10"

url("/sections/:id").exec("/sections/42") // { params: { id: 42 } }
url("/sections/:id").exec("/x/42") // null

url("/sections/:id").compile({ params: { id: 10 } }) // "/sections/10"
url("/search").compile({ query: { term: "shape" } }) // "/search?term=shape"

match("/sections/:id", "/sections/10") // { params: { id: 10 } }
match("/sections/:id", "/x") // null

validate("/sections/10") // true, found in the schema
validate("/x") // false, not found in the schema

Null schema

By having null as a URL schema, the URL builder can be used without schema validation:

const { url, match, validate } = createURLSchema(null);

url("/sections/:id", { params: { id: "x" } }) // "/sections/x"
match("/x/:name", "/x/intro") // { params: { name: "intro" } }
validate("/x") // true, all URLs are fine when there's no schema