Extends Context

Elysia는 시작하는 데 도움이 되는 작은 유틸리티들이 포함된 context를 제공합니다.

다음을 사용하여 Elysia의 context를 확장할 수 있습니다:

  1. Decorate
  2. State
  3. Resolve
  4. Derive

Decorate

싱글톤이며 불변인 값으로 모든 요청에서 공유됩니다.

typescript
import { Elysia } from 'elysia'

class Logger {
    log(value: string) {
        console.log(value)
    }
}

new Elysia()
    .decorate('logger', new Logger())
    .get('/', ({ logger }) => {
        logger.log('hi')

        return 'hi'
    })

데코레이트된 값은 context에서 읽기 전용 속성으로 사용할 수 있습니다. Decorate를 참조하세요.

State

모든 요청에서 공유되는 가변 참조입니다.

typescript
import { Elysia } from 'elysia'

new Elysia()
	.state('count', 0)
	.get('/', ({ count }) => {
		count++

		return count
	})

State는 모든 요청에서 공유되는 context.store에서 사용할 수 있습니다. State를 참조하세요.

Resolve / Derive

Decorate 값은 싱글톤으로 등록됩니다.

반면 ResolveDerive요청별로 context 값을 추상화할 수 있습니다.

typescript
import { Elysia } from 'elysia'

new Elysia()
	.derive(({ headers: { authorization } }) => ({
		authorization
	}))
	.get('/', ({ authorization }) => authorization)

반환된 값은 context에서 사용할 수 있습니다. 단, status는 예외로 클라이언트에 직접 전송되고 후속 핸들러를 중단합니다.

resolvederive의 구문은 유사하지만 서로 다른 사용 사례가 있습니다.

내부적으로 둘 다 라이프사이클의 syntactic sugar (타입 안전성 포함)입니다:

derivetransform을 기반으로 하므로 데이터가 아직 검증되지 않고 강제 변환/변환되지 않았습니다. 검증된 데이터가 필요한 경우 resolve를 사용하는 것이 좋습니다.

Scope

StateDecorate는 모든 요청과 인스턴스에서 공유됩니다.
ResolveDerive는 요청별로 캡슐화 범위를 가집니다 (라이프사이클 이벤트를 기반으로 하기 때문입니다).

플러그인에서 resolved/derived 값을 사용하려면 Scope를 선언해야 합니다.

typescript
import { Elysia } from 'elysia'

const plugin = new Elysia()
	.derive(
		{ as: 'scoped' }, 
		({ headers: { authorization } }) => ({
			authorization
		})
	)

new Elysia()
	.use(plugin)
	.get('/', ({ authorization }) => authorization)
	.listen(3000)

Assignment

Elysia의 context를 확장해 봅시다.

  1. Extract "query.age"

    Let's extract a "query.age" as "age". If it doesn't existed, return 401.

  2. Use "age"

    In a main handler of GET "/profile", return a value of "age" from the context

Show answer
resolve를 사용하여 query에서 age를 추출할 수 있습니다.
typescript
import { Elysia, t } from 'elysia'

class Logger {
	log(info: string) {
		console.log(info)
	}
}

new Elysia()
	.decorate('logger', new Logger())
	.onRequest(({ request, logger }) => {
		logger.log(`Request to ${request.url}`)
	})
	.guard({
		query: t.Optional(
			t.Object({
				age: t.Number({ min: 15 })
			})
		)
	})
	.resolve(({ query: { age }, status }) => {
		if(!age) return status(401)

		return { age }
	})
	.get('/profile', ({ age }) => age)
	.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)