扩展上下文

Elysia 提供了一个上下文,它配备了小工具,帮助您入门。

您可以通过以下方式扩展 Elysia 的上下文:

  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'
    })

装饰后的值将在上下文中作为只读属性可用,详见 Decorate

State

一个可变的引用,跨所有请求共享。

typescript
import { Elysia } from 'elysia'

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

		return store.count
	})

状态将在每个请求共享的 context.store 中可用,详见 State

Resolve / Derive

Decorate 的值注册为单例。

ResolveDerive 允许您每个请求抽象一个上下文值。

typescript
import { Elysia } from 'elysia'

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

任何返回的值都会在上下文中可用,除了状态,它将直接发送给客户端,并中止后续处理程序。

两个 resolvederive 的语法相似,但使用场景不同。

在底层,两者是一个语法糖 (具有类型安全) 的生命周期:

由于 derive 基于 transform,这意味着数据尚未验证且未强制/转换。如果您需要经过验证的数据,最好使用 resolve

作用域

StateDecorate 是跨所有请求和实例共享的。
ResolveDerive 是每个请求都有的,并具有封装作用域 (因为它们基于生命周期事件)

如果您想使用来自插件的解析/派生值,您需要声明一个 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)

练习

让我们尝试扩展 Elysia 的上下文。

  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 从查询中提取年龄。

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