Routing

The @stricjs/router component

Install the router and utilities:

bun add @stricjs/router @stricjs/utils

The router component provides the routing part for Stric, like Express or Fastify.

The utilities component has helpful utilities to parse and handle requests.

Define routes

You can define a route using [method](path, handler), for instance:

import { Router } from '@stricjs/router';  

export default new Router()
    .get('/', () => new Response('Hi'));

In the above example, we create a new router and this router will respond with Hi on every GET request to pathname /. The router can be served with export default or Bun.serve directly because it is a serve options object.

All method handlers

To add a handler for all methods, use app.all with the same parameter as above.

import { Router } from '@stricjs/router';

export default new Router()
    .all('/', () => new Response('Hi'));

Request methods

You can define a route with another request method as well.

Compares to the first example, this example add another handler which will run on every POST request to pathname /json. This handler will return an object as a response.

Parametric routes

You can parametric routes to retrieve data from URLs, works like Express and Fastify routes.

The type of req.params is inferred directly based on the path.

In this example, the server will respond to every route that matches /id/:id with the specified id parameter value in the URL. For example, if we send a GET request to pathname /id/90 we will get 90 as a response.

Wildcard

You can use the wildcard * to match the rest of the path.

This will respond to every request pathname starts with /private/.

Body parsing

Stric has a set of predefined body parser you can use.

Query parsing

The req.query parameter returns the query start index, include the ? character. You can parse query with @stricjs/utils:

Guarding

Guarding routes and validating data.

Routes

Guard routes work like wildcard but these routes are invoked first to check whether a specific sub-route should be handled.

Input validations

The @stricjs/utils component provides a simple and fast guard for checking user input.

Right now guard function is limited and does not support arrays (Arrays are very hard to compose).

Router groups

Using groups to split the route handlers.

This is a simple example which create a new group with the root set to /search, so the actual path that is registered is /search/:id, not :/id.

Special handlers

Stric provides a fast way to handle 404 when a route handler is not found.

Call use(404) to use the default 404 handler, use(404, handler) to add a custom handler.

For error handling, you can use the default 500 handler or register a custom handler the same way as the 404 handler.

Storing states

You can store states and methods for using in requests.

All states are stored in an object which is passed as a reference to the handler as the second argument, which mean you can change the properties of the store but not the store itself.

WebSocket

You can split routes for WebSocket handlers.

WebSocket routes cannot collide with other route handlers of the router, but you can still register route handlers with the same pathname but not GET method.

Details
  • WebSocket handlers are stored in a list, which is then attached with the upgrade data when server.upgrade(req, opts) is called.

  • The WebSocket handler is stored in the static route handlers list as a number which represents the index of the handler in the WebSocket handlers list.

  • When the path matches, the WebSocket handler is attached with the current Request object as a property _. The request object will be sent to the WebSocket event handlers as attached data.

  • Each WebSocket event handler will check if the specific handler for that event was registered. If it is registered the event handler will be executed.

Optimizations

Here are some optimizations you can do to make your Stric application faster.

Set the base URL

You can specify the exact base URL of your app to make path parsing faster. Note that will not works correctly if your app has subdomains.

Details
  • The createFetch function calculates the length of the base property.

  • The calculated length actually is the start index of the path part, so we can inject it directly into the code to check for query start index faster.

No path parsing

Set parsePath to false will skip slicing the path for matching routes and use the URL directly. This optimization will only work with the base optimization.

Details
  • Normally req.path is parsed to check the pathname.

  • If you disable path parsing req.path will not be usable.

Faster query parsing

If you only need the value of a single key in the query, you can create a specific parser with @stricjs/utils to search for the value. This function will return the value without decoding.

Using macros

Macros inject your code directly to your fetch without caching and calling the handler like usual, which can reduce response time. This feature should only be used for small handlers.

For returning a string response, macro has a shorthand.

Limitations

Because macro code is injected directly to the fetch function, it has some limitations.

  • Macros cannot access outside variables. To access variables outside the function scope you need to store it using app.store().

  • Macros code cannot use await. The fetch function is synchronous. You can return a promise, but can't use await.

  • Macros need proper parameters name. Code in macros that directly use the request and store need to have the same name as the variables in fetch.

Last updated

Was this helpful?