localhost
GET

Elysia는 기본적으로 최소한의 Context를 제공하며, state, decorate, derive, resolve를 사용하여 특정 요구 사항에 맞게 Context를 확장할 수 있습니다.
Elysia는 다음과 같은 다양한 사용 사례를 위해 Context를 확장할 수 있습니다:
다음 API를 사용하여 Context를 사용자 정의하여 Elysia의 컨텍스트를 확장할 수 있습니다:
다음과 같은 경우에만 Context를 확장해야 합니다:
그렇지 않으면 Context를 확장하는 것보다 값이나 함수를 별도로 정의하는 것이 좋습니다.
TIP
요청 및 응답과 관련된 속성 또는 자주 사용되는 함수를 관심사 분리를 위해 Context에 할당하는 것이 좋습니다.
State는 Elysia 앱 전체에서 공유되는 전역 변경 가능한 객체 또는 상태입니다.
state가 호출되면 호출 시점에 한 번 store 속성에 값이 추가되고 핸들러에서 사용할 수 있습니다.
import { Elysia } from 'elysia'
new Elysia()
.state('version', 1)
.get('/a', ({ store: { version } }) => version)
.get('/b', ({ store }) => store)
.get('/c', () => 'still ok')
.listen(3000)GET
wrapper 값이나 클래스를 사용하려면 decorate를 사용하세요.import { Elysia } from 'elysia'
new Elysia()
// ❌ TypeError: counter doesn't exist in store
.get('/error', ({ store }) => store.counter)Property 'counter' does not exist on type '{}'. .state('counter', 0)
// ✅ Because we assigned a counter before, we can now access it
.get('/', ({ store }) => store.counter)GET
TIP
할당하기 전에 state 값을 사용할 수 없습니다.
Elysia는 명시적인 타입이나 추가 TypeScript 제네릭 없이 자동으로 state 값을 store에 등록합니다.
상태를 변경하려면 실제 값을 사용하는 것보다 참조를 사용하여 변경하는 것이 좋습니다.
JavaScript에서 속성에 액세스할 때 객체 속성에서 원시 값을 새 값으로 정의하면 참조가 손실되고 값이 새로운 별도의 값으로 처리됩니다.
예를 들어:
const store = {
counter: 0
}
store.counter++
console.log(store.counter) // ✅ 1store.counter를 사용하여 속성에 액세스하고 변경할 수 있습니다.
그러나 counter를 새 값으로 정의하면
const store = {
counter: 0
}
let counter = store.counter
counter++
console.log(store.counter) // ❌ 0
console.log(counter) // ✅ 1원시 값이 새 변수로 재정의되면 참조 "링크"가 손실되어 예상치 못한 동작이 발생합니다.
이는 전역 변경 가능한 객체이므로 store에도 적용될 수 있습니다.
import { Elysia } from 'elysia'
new Elysia()
.state('counter', 0)
// ✅ Using reference, value is shared
.get('/', ({ store }) => store.counter++)
// ❌ Creating a new variable on primitive value, the link is lost
.get('/error', ({ store: { counter } }) => counter)GET
decorate는 호출 시점에 추가 속성을 Context에 직접 할당합니다.
import { Elysia } from 'elysia'
class Logger {
log(value: string) {
console.log(value)
}
}
new Elysia()
.decorate('logger', new Logger())
// ✅ defined from the previous line
.get('/', ({ logger }) => {
logger.log('hi')
return 'hi'
})Context의 기존 속성에서 값을 가져와 새 속성을 할당합니다.
Derive는 요청이 발생할 때 transform 라이프사이클에서 할당되어 기존 속성에서 새 속성을 "파생"(생성)할 수 있습니다.
import { Elysia } from 'elysia'
new Elysia()
.derive(({ headers }) => {
const auth = headers['authorization']
return {
bearer: auth?.startsWith('Bearer ') ? auth.slice(7) : null
}
})
.get('/', ({ bearer }) => bearer)GET
derive는 새 요청이 시작되면 할당되므로 store 및 decorate가 할 수 없는 headers, query, body와 같은 요청 속성에 액세스할 수 있습니다.
derive와 유사하지만 타입 무결성을 보장합니다.
Resolve는 컨텍스트에 새 속성을 할당할 수 있습니다.
Resolve는 beforeHandle 라이프사이클 또는 유효성 검사 후에 호출되어 요청 속성을 안전하게 resolve할 수 있습니다.
import { Elysia, t } from 'elysia'
new Elysia()
.guard({
headers: t.Object({
bearer: t.String({
pattern: '^Bearer .+$'
})
})
})
.resolve(({ headers }) => {
return {
bearer: headers.bearer.slice(7)
}
})
.get('/', ({ bearer }) => bearer)resolve 및 derive는 transform 및 beforeHandle 라이프사이클을 기반으로 하므로 resolve 및 derive에서 오류를 반환할 수 있습니다. derive에서 오류가 반환되면 Elysia는 조기 종료하고 오류를 응답으로 반환합니다.
import { Elysia } from 'elysia'
new Elysia()
.derive(({ headers, status }) => {
const auth = headers['authorization']
if(!auth) return status(400)
return {
bearer: auth?.startsWith('Bearer ') ? auth.slice(7) : null
}
})
.get('/', ({ bearer }) => bearer)state, decorate는 Context에 속성을 할당하기 위해 다음과 같은 유사한 API 패턴을 제공합니다:
derive는 기존 값에 의존하므로 remap과만 사용할 수 있습니다.
state 및 decorate를 사용하여 key-value 패턴을 사용하여 값을 할당할 수 있습니다.
import { Elysia } from 'elysia'
class Logger {
log(value: string) {
console.log(value)
}
}
new Elysia()
.state('counter', 0)
.decorate('logger', new Logger())이 패턴은 단일 속성을 설정할 때 가독성이 뛰어납니다.
여러 속성을 할당하는 것은 단일 할당을 위해 객체에 포함하는 것이 좋습니다.
import { Elysia } from 'elysia'
new Elysia()
.decorate({
logger: new Logger(),
trace: new Trace(),
telemetry: new Telemetry()
})객체는 여러 값을 설정하기 위한 덜 반복적인 API를 제공합니다.
Remap은 함수 재할당입니다.
속성 이름을 바꾸거나 제거하는 것과 같이 기존 값에서 새 값을 만들 수 있습니다.
함수를 제공하고 값을 재할당하기 위해 완전히 새로운 객체를 반환합니다.
import { Elysia } from 'elysia'
new Elysia()
.state('counter', 0)
.state('version', 1)
.state(({ version, ...store }) => ({
...store,
elysiaVersion: 1
}))
// ✅ Create from state remap
.get('/elysia-version', ({ store }) => store.elysiaVersion)
// ❌ Excluded from state remap
.get('/version', ({ store }) => store.version)Property 'version' does not exist on type '{ elysiaVersion: number; counter: number; }'.GET
기존 값에서 새 초기 값을 만들려면 state remap을 사용하는 것이 좋습니다.
그러나 Elysia는 remap이 초기 값만 할당하므로 이 접근 방식에서 반응성을 제공하지 않는다는 점에 유의해야 합니다.
TIP
remap을 사용하면 Elysia는 반환된 객체를 새 속성으로 취급하여 객체에서 누락된 속성을 제거합니다.
더 나은 경험을 제공하기 위해 일부 플러그인에는 하나씩 remap하기에 부담스러울 수 있는 많은 속성 값이 있을 수 있습니다.
prefix 및 suffix로 구성된 Affix 함수를 사용하면 인스턴스의 모든 속성을 remap할 수 있습니다.
import { Elysia } from 'elysia'
const setup = new Elysia({ name: 'setup' })
.decorate({
argon: 'a',
boron: 'b',
carbon: 'c'
})
const app = new Elysia()
.use(setup)
.prefix('decorator', 'setup')
.get('/', ({ setupCarbon, ...rest }) => setupCarbon)GET
플러그인의 속성을 손쉽게 대량으로 remap하여 플러그인의 이름 충돌을 방지할 수 있습니다.
기본적으로 affix는 명명 규칙으로 camelCase로 속성을 remap하여 런타임 및 타입 레벨 코드를 자동으로 처리합니다.
일부 조건에서는 플러그인의 all 속성을 remap할 수도 있습니다:
import { Elysia } from 'elysia'
const setup = new Elysia({ name: 'setup' })
.decorate({
argon: 'a',
boron: 'b',
carbon: 'c'
})
const app = new Elysia()
.use(setup)
.prefix('all', 'setup')
.get('/', ({ setupCarbon, ...rest }) => setupCarbon)