Guard

애플리케이션에 여러 hook을 적용해야 할 때, hook을 여러 번 반복하는 대신 guard를 사용하여 애플리케이션에 hook을 일괄적으로 추가할 수 있습니다.

typescript
import { Elysia, t } from 'elysia'

new Elysia()
	.onBeforeHandle(({ query: { name }, status }) => { 
		if(!name) return status(401) 
	}) 
	.onBeforeHandle(({ query: { name } }) => { 
		console.log(name) 
	}) 
	.onAfterResponse(({ responseValue }) => { 
		console.log(responseValue) 
	}) 
	.guard({ 
		beforeHandle: [ 
			({ query: { name }, status }) => { 
				if(!name) return status(401) 
			}, 
			({ query: { name } }) => { 
				console.log(name) 
			} 
		], 
		afterResponse({ responseValue }) { 
			console.log(responseValue) 
		} 
	}) 
	.get(
		'/auth',
		({ query: { name = 'anon' } }) => `Hello ${name}!`,
		{
			query: t.Object({
				name: t.String()
			})
		}
	)
	.get(
		'/profile',
		({ query: { name = 'anon' } }) => `Hello ${name}!`,
		{
			query: t.Object({
				name: t.String()
			})
		}
	)
	.listen(3000)

뿐만 아니라 guard를 사용하여 여러 route에 schema를 적용할 수도 있습니다.

typescript
import { Elysia, t } from 'elysia'

new Elysia()
	.guard({
		beforeHandle: [
			({ query: { name }, status }) => {
				if(!name) return status(401)
			},
			({ query: { name } }) => {
				console.log(name)
			}
		],
		afterResponse({ responseValue }) {
			console.log(responseValue)
		},
		query: t.Object({ 
			name: t.String() 
		}) 
	})
	.get(
		'/auth',
		({ query: { name = 'anon' } }) => `Hello ${name}!`,
		{ 
			query: t.Object({ 
				name: t.String() 
			}) 
		} 
	)
	.get(
		'/profile',
		({ query: { name = 'anon' } }) => `Hello ${name}!`,
		{ 
			query: t.Object({ 
				name: t.String() 
			}) 
		} 
	)
	.listen(3000)

이것은 같은 인스턴스에서 .guard가 호출된 이후의 모든 route에 hook과 schema를 적용합니다.

자세한 내용은 Guard를 참조하세요.

과제

2가지 유형의 hook을 실습해 봅시다.

  1. Authentication

    Let's add a simple authentication middleware to GET "/auth" endpoint using beforeHandle hook. If query `name` is provided, we will let the request pass, otherwise we will return 401 status.

  2. Interceptor Hook

    Now, let's create another endpoint GET "/profile" that has the same logic with authentication. We can refactor our code by using interceptor hook to avoid duplication.

Show answer

beforeHandle을 사용하여 handler에 도달하기 전에 요청을 가로채고, status 메서드로 응답을 반환할 수 있습니다.

typescript
import { Elysia } from 'elysia'

new Elysia()
	.onBeforeHandle(({ query: { name }, status }) => {
		if(!name) return status(401)
	})
	.get('/auth', ({ query: { name = 'anon' } }) => {
		return `Hello ${name}!`
	})
	.get('/profile', ({ query: { name = 'anon' } }) => {
		return `Hello ${name}!`
	})
	.listen(3000)
  • index.ts

Error

Error: No Elysia server is running in index.ts
Did you forget to call `.listen()`?
    at parse (file:///vercel/path0/docs/.vitepress/.temp/utils.J44kKQwQ.js:202:66)
    at file:///vercel/path0/docs/.vitepress/.temp/utils.J44kKQwQ.js:240:30
    at new Promise (<anonymous>)
    at execute (file:///vercel/path0/docs/.vitepress/.temp/utils.J44kKQwQ.js:238:49)
    at Proxy.run (file:///vercel/path0/docs/.vitepress/.temp/store.CFqL75-f.js:190:51)
    at Proxy.wrappedAction (file:///vercel/path0/node_modules/pinia/dist/pinia.mjs:1394:26)
    at setup (file:///vercel/path0/docs/.vitepress/.temp/playground.eEZCBItr.js:133:50)
    at playground_vue_vue_type_script_setup_true_lang_default.setup (file:///vercel/path0/docs/.vitepress/.temp/playground.eEZCBItr.js:438:22)
    at callWithErrorHandling (/vercel/path0/node_modules/@vue/runtime-core/dist/runtime-core.cjs.prod.js:86:19)
    at setupStatefulComponent (/vercel/path0/node_modules/@vue/runtime-core/dist/runtime-core.cjs.prod.js:6365:25)