Encapsulation

Elysia hook은 자신의 인스턴스에만 캡슐화됩니다.

새로운 인스턴스를 생성하면 다른 인스턴스와 hook을 공유하지 않습니다.

ts
import { Elysia } from 'elysia'

const profile = new Elysia()
	.onBeforeHandle(
		({ query: { name }, status }) => {
			if(!name)
				return status(401)
		}
	)
	.get('/profile', () => 'Hi!')

new Elysia()
	.use(profile)
	.patch('/rename', () => 'Ok! XD')
	.listen(3000)
localhost

GET

URL 바에서 경로를 /rename으로 변경하고 결과를 확인해 보세요


Elysia는 명시적으로 지정하지 않는 한 lifecycle을 격리합니다.

이는 JavaScript의 export와 유사하며, 모듈 외부에서 사용할 수 있도록 함수를 export해야 합니다.

lifecycle을 다른 인스턴스로 "export"하려면 scope를 지정해야 합니다.

Scope

3가지 scope가 있습니다:

  1. local (기본값) - 현재 인스턴스와 하위 항목에만 적용
  2. scoped - 부모, 현재 인스턴스 및 하위 항목에 적용
  3. global - 플러그인을 적용하는 모든 인스턴스에 적용 (모든 부모, 현재 및 하위 항목)

우리의 경우, 직접 부모인 app에 로그인 확인을 적용하고 싶으므로 scoped 또는 global을 사용할 수 있습니다.

ts
import { Elysia } from 'elysia'

const profile = new Elysia()
	.onBeforeHandle(
		{ as: 'scoped' }, 
		({ cookie }) => {
			throwIfNotSignIn(cookie)
		}
	)
	.get('/profile', () => 'Hi there!')

const app = new Elysia()
	.use(profile)
	// This has sign in check
	.patch('/rename', ({ body }) => updateProfile(body))
localhost

GET

lifecycle을 "scoped"로 캐스팅하면 lifecycle을 부모 인스턴스로 export합니다. "global"은 플러그인이 있는 모든 인스턴스로 lifecycle을 export합니다.

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

Guard

lifecycle과 마찬가지로 schema도 자체 인스턴스에 캡슐화됩니다.

lifecycle과 유사하게 guard scope를 지정할 수 있습니다.

typescript
import { Elysia } from 'elysia'

const user = new Elysia()
	.guard({
		as: 'scoped', 
		query: t.Object({
			age: t.Number(),
			name: t.Optional(t.String())
		}),
		beforeHandle({ query: { age }, status }) {
			if(age < 18) return status(403)
		}
	})
	.get('/profile', () => 'Hi!')
	.get('/settings', () => 'Settings')

모든 hook이 선언 이후의 모든 route에 영향을 미친다는 점을 유념하는 것이 매우 중요합니다.

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

과제

nameCheckageCheck에 대한 scope를 정의하여 앱이 작동하도록 해봅시다.

  1. Name Check

    Make sure that user provides `name` query is applied to **only instance that use plugin** (self, and parent)

  2. Age Check

    Make sure that user is at least 18 years old is applied **all** endpoint

Show answer

다음과 같이 scope를 수정할 수 있습니다:

  1. nameCheck scope를 scoped로 수정
  2. ageCheck scope를 global로 수정
typescript
import { Elysia, t } from 'elysia'

const nameCheck = new Elysia()
	.onBeforeHandle(
		{ as: 'scoped' }, 
		({ query: { name }, status }) => {
			if(!name) return status(401)
		}
	)

const ageCheck = new Elysia()
	.guard({
		as: 'global', 
		query: t.Object({
			age: t.Number(),
			name: t.Optional(t.String())
		}),
		beforeHandle({ query: { age }, status }) {
			if(age < 18) return status(403)
		}
	})

const name = new Elysia()
	.use(nameCheck)
	.patch('/rename', () => 'Ok! XD')

const profile = new Elysia()
	.use(ageCheck)
	.use(name)
	.get('/profile', () => 'Hi!')

new Elysia()
	.use(profile)
	.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)