Skip to content

t8js/url-shape

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

89 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 validation libs like Zod

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

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

🔹 createURLSchema() accepts a URL schema defined with any validation lib supporting the Standard Schema spec, including Zod, ArkType, Valibot, or Yup.

🔹 With Zod, mind 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 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"

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, validate } = createURLSchema(null);

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