Untitled Page

ID: 2214https://elysiajs.com/essential/route.md
Source

Routing

Web servers use the request's path and method to look up the correct resource, known as "routing".

We can define a route with HTTP verb method, a path and a function to execute when matched.

import { Elysia } from 'elysia'

new Elysia()
    .get('/', 'hello')
    .get('/hi', 'hi')
    .listen(3000)

We can access the web server by going to http://localhost:3000

By default, web browsers will send a GET method when visiting a page.

::: tip Using the interactive browser above, hover on the blue highlight area to see different results between each path. :::

Path type

Path in Elysia can be grouped into 3 types:

  • static paths - static string to locate the resource
  • dynamic paths - segment can be any value
  • wildcards - path until a specific point can be anything

You can use all of the path types together to compose a behavior for your web server.

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/1', 'static path')
    .get('/id/:id', 'dynamic path')
    .get('/id/*', 'wildcard path')
    .listen(3000)

Static Path

Static path is a hardcoded string to locate the resource on the server.

import { Elysia } from 'elysia'

new Elysia()
	.get('/hello', 'hello')
	.get('/hi', 'hi')
	.listen(3000)

Dynamic path

Dynamic paths match some part and capture the value to extract extra information.

To define a dynamic path, we can use a colon : followed by a name.

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id)
                      // ^?
    .listen(3000)

Here, a dynamic path is created with /id/:id. Which tells Elysia to capture the value :id segment with value like /id/1, /id/123, /id/anything.

When requested, the server should return the response as follows:

PathResponse
/id/11
/id/123123
/id/anythinganything
/id/anything?name=saltanything
/idNot Found
/id/anything/restNot Found

Dynamic paths are great to include things like IDs that can be used later.

We refer to the named variable path as path parameter or params for short.

Multiple path parameters

You can have as many path parameters as you like, which will then be stored into a params object.

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/:id', ({ params: { id } }) => id)
    .get('/id/:id/:name', ({ params: { id, name } }) => id + ' ' + name)
                             // ^?
    .listen(3000)

The server will respond as follows:

PathResponse
/id/11
/id/123123
/id/anythinganything
/id/anything?name=saltanything
/idNot Found
/id/anything/restanything rest

Optional path parameters

Sometime we might want a static and dynamic path to resolve the same handler.

We can make a path parameter optional by adding a question mark ? after the parameter name.

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/:id?', ({ params: { id } }) => `id ${id}`)
                          // ^?
    .listen(3000)

Wildcards

Dynamic paths allow capturing a single segment while wildcards allow capturing the rest of the path.

To define a wildcard, we can use an asterisk *.

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/*', ({ params }) => params['*'])
                    // ^?
    .listen(3000)

Path priority

Elysia has a path priorities as follows:

  1. static paths
  2. dynamic paths
  3. wildcards

If the path is resolved as the static wild dynamic path is presented, Elysia will resolve the static path rather than the dynamic path

import { Elysia } from 'elysia'

new Elysia()
    .get('/id/1', 'static path')
    .get('/id/:id', 'dynamic path')
    .get('/id/*', 'wildcard path')
    .listen(3000)

HTTP Verb

HTTP defines a set of request methods to indicate the desired action to be performed for a given resource

There are several HTTP verbs, but the most common ones are:

GET

Requests using GET should only retrieve data.

POST

Submits a payload to the specified resource, often causing state change or side effect.

PUT

Replaces all current representations of the target resource using the request's payload.

PATCH

Applies partial modifications to a resource.

DELETE

Deletes the specified resource.


To handle each of the different verbs, Elysia has a built-in API for several HTTP verbs by default, similar to Elysia.get

import { Elysia } from 'elysia'

new Elysia()
    .get('/', 'hello')
    .post('/hi', 'hi')
    .listen(3000)

Elysia HTTP methods accepts the following parameters:

  • path: Pathname
  • function: Function to respond to the client
  • hook: Additional metadata

You can read more about the HTTP methods on HTTP Request Methods.

Custom Method

We can accept custom HTTP Methods with Elysia.route.

import { Elysia } from 'elysia'

const app = new Elysia()
    .get('/get', 'hello')
    .post('/post', 'hi')
    .route('M-SEARCH', '/m-search', 'connect') // [!code ++]
    .listen(3000)

Elysia.route accepts the following:

  • method: HTTP Verb
  • path: Pathname
  • function: Function to response to the client
  • hook: Additional metadata

::: tip Based on RFC 7231, HTTP Verb is case-sensitive.

It's recommended to use the UPPERCASE convention for defining a custom HTTP Verb with Elysia. :::

ALL method

Elysia provides an Elysia.all for handling any HTTP method for a specified path using the same API like Elysia.get and Elysia.post

import { Elysia } from 'elysia'

new Elysia()
    .all('/', 'hi')
    .listen(3000)

Any HTTP method that matches the path, will be handled as follows:

PathMethodResult
/GEThi
/POSThi
/DELETEhi

Handle

Most developers use REST clients like Postman, Insomnia or Hoppscotch to test their API.

However, Elysia can be programmatically test using Elysia.handle.

import { Elysia } from 'elysia'

const app = new Elysia()
    .get('/', 'hello')
    .post('/hi', 'hi')
    .listen(3000)

app.handle(new Request('http://localhost/')).then(console.log)

Elysia.handle is a function to process an actual request sent to the server.

::: tip Unlike unit test's mock, you can expect it to behave like an actual request sent to the server.

But also useful for simulating or creating unit tests. :::

Group

When creating a web server, you would often have multiple routes sharing the same prefix:

import { Elysia } from 'elysia'

new Elysia()
    .post('/user/sign-in', 'Sign in')
    .post('/user/sign-up', 'Sign up')
    .post('/user/profile', 'Profile')
    .listen(3000)

This can be improved with Elysia.group, allowing us to apply prefixes to multiple routes at the same time by grouping them together:

import { Elysia } from 'elysia'

new Elysia()
    .group('/user', (app) =>
        app
            .post('/sign-in', 'Sign in')
            .post('/sign-up', 'Sign up')
            .post('/profile', 'Profile')
    )
    .listen(3000)

This code behaves the same as our first example and should be structured as follows:

PathResult
/user/sign-inSign in
/user/sign-upSign up
/user/profileProfile

.group() can also accept an optional guard parameter to reduce boilerplate of using groups and guards together:

import { Elysia, t } from 'elysia'

new Elysia()
    .group(
        '/user',
        {
            body: t.Literal('Rikuhachima Aru')
        },
        (app) => app
            .post('/sign-in', 'Sign in')
            .post('/sign-up', 'Sign up')
            .post('/profile', 'Profile')
    )
    .listen(3000)

You may find more information about grouped guards in scope.

Prefix

We can separate a group into a separate plugin instance to reduce nesting by providing a prefix to the constructor.

import { Elysia } from 'elysia'

const users = new Elysia({ prefix: '/user' })
    .post('/sign-in', 'Sign in')
    .post('/sign-up', 'Sign up')
    .post('/profile', 'Profile')

new Elysia()
    .use(users)
    .get('/', 'hello world')
    .listen(3000)