url-shape
Type-safe schema-based URL builder
🔹 Create a URL schema with a schema lib like 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'])),
}),
},
});
If you are using 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.
🔹 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
🔹 The URL builder can also 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