Skip to content

Scope ​

As mentioned, global Lifecycle and Schema apply to every route after the registration, allowing the use of multiple routes.

However, in a real-world scenario, the global event is hard to trace and control properly. This is why Elysia has an encapsulation scope to ensure that the event will only apply to a certain group of routes.

Guard ​

Guard allows us to apply hook and schema into multiple routes all at once.

typescript
import { Elysia, t } from 'elysia'

new Elysia()
    .guard( 
        { 
            body: t.Object({ 
                username: t.String(), 
                password: t.String() 
            }) 
        }, 
        (app) => 
            app
                .post('/sign-up', ({ body }) => signUp(body))
                .post('/sign-in', ({ body }) => signIn(body), {
                    beforeHandle: isUserExists
                })
    )
    .get('/', () => 'hi')
    .listen(3000)
import { Elysia, t } from 'elysia'

new Elysia()
    .guard( 
        { 
            body: t.Object({ 
                username: t.String(), 
                password: t.String() 
            }) 
        }, 
        (app) => 
            app
                .post('/sign-up', ({ body }) => signUp(body))
                .post('/sign-in', ({ body }) => signIn(body), {
                    beforeHandle: isUserExists
                })
    )
    .get('/', () => 'hi')
    .listen(3000)

This code applies validation for body to both '/sign-in' and '/sign-up' instead of inlining the schema one by one but applies not to '/'.

We can summarize the route validation as the following:

PathHas validation
/sign-up✅
/sign-in✅
/❌

Guard accepts the same parameter as inline hook, the only difference is that you can apply hook to multiple routes in the scope.

This means that the code above is translated into:

typescript
import { Elysia, t } from 'elysia'

new Elysia()
    .post('/sign-up', ({ body }) => signUp(body), {
        body: t.Object({
            username: t.String(),
            password: t.String()
        })
    })
    .post('/sign-in', (({ body }) => signIn(body), {
        beforeHandle: isUserExists,
        body: t.Object({
            username: t.String(),
            password: t.String()
        })
    })
    .get('/', () => 'hi')
    .listen(3000)
import { Elysia, t } from 'elysia'

new Elysia()
    .post('/sign-up', ({ body }) => signUp(body), {
        body: t.Object({
            username: t.String(),
            password: t.String()
        })
    })
    .post('/sign-in', (({ body }) => signIn(body), {
        beforeHandle: isUserExists,
        body: t.Object({
            username: t.String(),
            password: t.String()
        })
    })
    .get('/', () => 'hi')
    .listen(3000)

Grouped Guard ​

We can use a group with prefixes by providing 3 parameters to the group.

  1. Prefix - Route prefix
  2. Guard - Schema
  3. Scope - Elysia app callback

With the same API as guard apply to the 2nd parameter, instead of nesting group and guard together.

typescript
// From nested group guard
app.group('/v1', (app) =>
    app.guard(
        {
            body: t.Literal('Rikuhachima Aru')
        },
        (app) => app.get('/student', () => 'Rikuhachima Aru')
    )
)

// Remove the guard
app.group(
    '/v1',
    (app) => app.guard( 
    {
        body: t.Literal('Rikuhachima Aru')
    },
    (app) => app.get('/student', () => 'Rikuhachima Aru')
    ) 
)

// Inline to group 2nd parameter instead
app.group(
    '/v1',
    {
        body: t.Literal('Rikuhachima Aru')
    },
    (app) => app.get('/student', () => 'Rikuhachima Aru')
)
// From nested group guard
app.group('/v1', (app) =>
    app.guard(
        {
            body: t.Literal('Rikuhachima Aru')
        },
        (app) => app.get('/student', () => 'Rikuhachima Aru')
    )
)

// Remove the guard
app.group(
    '/v1',
    (app) => app.guard( 
    {
        body: t.Literal('Rikuhachima Aru')
    },
    (app) => app.get('/student', () => 'Rikuhachima Aru')
    ) 
)

// Inline to group 2nd parameter instead
app.group(
    '/v1',
    {
        body: t.Literal('Rikuhachima Aru')
    },
    (app) => app.get('/student', () => 'Rikuhachima Aru')
)

Plugin ​

By default plugin will only apply hook to itself and descendants only.

If the hook is registered in a plugin, instances that inherit the plugin will NOT inherit hooks and schema.

typescript
const plugin = new Elysia()
    .onBeforeHandle(() => {
        console.log('hi')
    })
    .get('/child', () => 'log hi')

const main = new Elysia()
    .use(plugin)
    .get('/parent', () => 'not log hi')
const plugin = new Elysia()
    .onBeforeHandle(() => {
        console.log('hi')
    })
    .get('/child', () => 'log hi')

const main = new Elysia()
    .use(plugin)
    .get('/parent', () => 'not log hi')

To apply hook to globally, we need to specify hook as global.

typescript
const plugin = new Elysia()
    .onBeforeHandle({ as: 'global' }, () => {
        console.log('hi')
    })
    .get('/child', () => 'log hi')

const main = new Elysia()
    .use(plugin)
    .get('/parent', () => 'log hi')
const plugin = new Elysia()
    .onBeforeHandle({ as: 'global' }, () => {
        console.log('hi')
    })
    .get('/child', () => 'log hi')

const main = new Elysia()
    .use(plugin)
    .get('/parent', () => 'log hi')