Route

Composition

Composition enables patterns like path prefixing and more complex middleware chains, without requiring routers or frameworks.

Fundamentally, composition allows us to prevent repeating ourselves. In contrast to schema, which overwrite previous schema, paths and middleware are appended.

Composing Paths

To avoid repeating common path param elements, we might sometimes wish to add path prefixes. For example, we might prefix our entire api with /api or /v2. Additionally, we might want to group routes under a group like /posts/*.

const  = ("/api")
 
const  = .("/post")
 
const  = .("get").(() => {})
 
// Even typescript understands
type 
type Path = "/api/post"
Path
= Route.<typeof >

Composing Middleware

Composing middleware is simple and powerful using webroutes. It makes it easier to understand what middleware each route depends on and means type-safety is retained throughout.

// Define base route with auth middleware
const  = ()
	.(() => {
		const  = .
			.("Authorization")
			?.("Bearer ", "");
 
		if() return {  }
 
		return .({ : "UNAUTHORIZED" }, { : 401 });
	})
 
 
// Define a route which employs the middleware
// GET /me

	.("/me")
	.("get")
	.((, {  }) => {
		const {  } = 
 
		// TODO: Get user
	})

Middleware can be chained too.

// Extend the `authedRoute` base
const  = 
 
	// This middleware is run in addition to the `authedRoute` middleware.
	// This does not affect the `authedRoute` base or its other descendants.
	.((, {  }) => {
		if((.)) {
			return 
		}
 
		return .({ : "UNAUTHORIZED", }, { : 401 })
	})
 
 
// GET /me

	.("/admins-only")
	.("get")
	.(() => {
		// ...
	})

For more complex middleware mixing and matching you may also want to extract the middleware logic into seperate functions.

Composing Schema, Methods, ...etc.

While middleware and paths benefit from composition the most, schema and methods can also be composed. Although, unlike middleware and paths, these override previous declarations.

 
const  = ()
	.(.({ 
		: .().(),
		: .().()
	}))
	.("get")
 
const  = .(() => {})
 
const  = 
	.(.({
		: .(["A4", "A3", "A2"])
	}))
	.(async (, {  }) => {
		const { , ... } = await ("query")
	})

On this page