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를 참조하세요.

과제 ​

nameCheck와 ageCheck에 대한 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)