跳到主要内容

API 包

api 包是 VEF 请求处理层的基础。它定义了核心抽象 — 资源、操作、请求/响应类型和处理器解析 — 所有其他包都构建在此之上。

API 参考

生成的 公开 API 索引 是所有 exported symbol、exported field 和 exported method 的无遗漏清单。本指南负责说明这些 surface 背后的受支持行为和运行时 contract。

本指南涵盖的 API 组:

分组公开 API
resource 和 kindapi.Resource, api.Kind, api.KindRPC, api.KindREST, api.ValidateActionName(action, kind) error, api.NewRPCResource(name, opts...), api.NewRESTResource(name, opts...), api.WithVersion(v), api.WithAuth(config), api.WithOperations(specs...)
engine 和 routing 扩展api.Engine, api.RouterStrategy, api.Middleware
operationsapi.OperationSpec, api.Operation, api.RateLimitConfig, api.OperationsProvider, api.OperationsCollector
request modelapi.Identifier, api.Request, api.Params, api.Meta, api.P, api.M
authapi.AuthConfig, api.Public(), api.BearerAuth(), api.SignatureAuth(), api.IPAuth(...), api.AuthStrategy, api.AuthStrategyRegistry
handler 扩展api.HandlerResolver, api.HandlerAdapter, api.HandlerParamResolver, api.FactoryParamResolver
audit、headers、versions、errorsapi.AuditEvent, api.SubscribeAuditEvent, api.HeaderXMetaPrefix, api.HeaderXTimestamp, api.HeaderXNonce, api.HeaderXSignature, api.HeaderXAppID, api.VersionV1, api.VersionV9, api.ErrInvalidRequestParams, api.ErrInvalidRequestMeta, api.ErrInvalidParamsType, api.ErrInvalidMetaType

架构

api.Engine
├── Register(resources...) — 注册资源
├── Mount(router) — 挂载到 Fiber
└── Lookup(id) — 运行时查找操作

api.Resource
├── Kind() — RPC 或 REST
├── Name() — 资源路径(如 "sys/user")
├── Version() — API 版本(如 "v1")
├── Auth() — 认证配置
└── Operations() — 操作规格列表

api.OperationSpec → api.Operation(运行时)

Resource

Resource 将相关的 API 操作归组到一个公共路径下。VEF 提供两种资源类型:

创建资源

// RPC 资源 — 使用 snake_case 命名 action
resource := api.NewRPCResource("sys/user")

// REST 资源 — 使用 HTTP 动词
resource := api.NewRESTResource("sys/user")

// 带选项
resource := api.NewRPCResource("sys/user",
api.WithVersion("v2"),
api.WithAuth(api.BearerAuth()),
api.WithOperations(
api.OperationSpec{Action: "create", Handler: createHandler},
api.OperationSpec{Action: "find_page", Handler: findPageHandler},
),
)

资源类型(Kind)

类型常量名称格式Action 格式示例
RPCapi.KindRPCsnake_case + / 分隔snake_casesys/usercreatefind_page
RESTapi.KindRESTkebab-case + / 分隔<动词><动词> <子资源>sys/usergetpostget user-friends

Kind.String()KindRPC 返回 rpc,对 KindREST 返回 rest,其他值返回 unknown

资源名称规则

规则合法非法
必须以小写字母开头usersys/userUser1user
不能以斜杠开头/结尾sys/user/sys/user/
不能有连续斜杠sys/usersys//user
RPC:snake_case 分段sys/data_dictsys/data-dict
REST:kebab-case 分段sys/data-dictsys/data_dict

资源选项

选项说明
api.WithVersion(v)覆盖引擎的默认版本(如 "v2"
api.WithAuth(config)设置资源级认证
api.WithOperations(specs...)直接提供操作规格

api.NewRPCResourceapi.NewRESTResource 会在构造期校验 resource name、version,以及通过直接 api.WithOperations(...) 传入的 specs;校验失败会 panic。api.ValidateActionName(action, kind) 是公开函数,适合动态构建 resource 的代码在创建 OperationSpec 前复用框架同一套 RPC/REST action 校验规则。

REST action 校验接受这些小写 method token:getpostputdeletepatchheadoptionstraceconnectall。 sub-resource 路径可以包含 /,但每一段都必须是 kebab-case;动态 Fiber 参数如 /:id 不会被公开 validator 接受。

Resource 接口

type Resource interface {
Kind() Kind
Name() string
Version() string
Auth() *AuthConfig
Operations() []OperationSpec
}

使用 CRUD builder 时,通常嵌入 api.Resource 和 CRUD provider。内置 collector 会读取直接的 Resource.Operations() specs,也会读取匿名嵌入的 OperationsProvider。直接 WithOperations(...) 传入的 specs 会由 resource constructor 校验。engine 注册期间,收集到的 operation specs 必须有非空 action;自定义 OperationsProvider 仍应产出已经满足 api.ValidateActionName(...) 的 action 字符串。

OperationSpec

OperationSpec 是 API 端点的静态定义:

type OperationSpec struct {
Action string // Action 名(如 "create"、"find_page")
EnableAudit bool // 启用审计日志
Timeout time.Duration // 请求超时
Public bool // 无需认证
RequiredPermission string // 所需权限令牌(v0.24 起从 PermToken 重命名)
RateLimit *RateLimitConfig // 限流配置
Handler any // 业务处理函数
}

运行期 engine 会把它物化为带最终 AuthRateLimit 指针的 Operation, 供 router strategy、middleware、诊断和测试使用。OperationRequest 都嵌入了 Identifier,所以 Identifier.String() 会提升为 Operation.String()Request.String()

Operation 默认化规则:

字段运行时行为
Action必填;直接 WithOperations(...) 传入的 specs 会由 resource constructor 按 resource kind 校验;engine 注册会拒绝空 action
EnableAudit直接复制到运行时 operation
Timeout非正值使用 engine 默认值;未覆盖时默认 30s
Publictrue 时先解析为 api.Public(),优先于资源级/default auth
RequiredPermission非空时写入 auth options 中的 required permission token
RateLimitnil 使用 engine 默认——配置了 vef.api.rate_limit 时用配置值,否则 Max=100Period=5m(v0.38);自定义 RateLimitConfig 会替换默认值
HandlerRPC 可在省略时从 action 推断;REST 必须显式提供 handler

配合 CRUD Builder 使用

大多数操作通过 CRUD builder 定义,而非直接使用 OperationSpec

type UserResource struct {
api.Resource

crud.FindPage[User, UserSearch]
crud.Create[User, UserParams]
crud.Update[User, UserParams]
crud.Delete[User]
}

func NewUserResource() *UserResource {
return &UserResource{
Resource: api.NewRPCResource("sys/user"),
FindPage: crud.NewFindPage[User, UserSearch]().RequiredPermission("sys:user:query"),
Create: crud.NewCreate[User, UserParams]().RequiredPermission("sys:user:create"),
Update: crud.NewUpdate[User, UserParams]().RequiredPermission("sys:user:update"),
Delete: crud.NewDelete[User]().RequiredPermission("sys:user:delete"),
}
}

配合自定义 Handler 使用

对于非 CRUD 操作,使用 WithOperations 或实现 OperationsProvider

resource := api.NewRPCResource("sys/user",
api.WithOperations(
api.OperationSpec{
Action: "reset_password",
Handler: resetPasswordHandler,
RequiredPermission: "sys:user:reset_password",
},
),
)

Identifier

每个操作都有唯一的 Identifier

type Identifier struct {
Resource string `json:"resource" form:"resource" validate:"required,alphanum_us_slash" label_i18n:"api_request_resource"`
Action string `json:"action" form:"action" validate:"required" label_i18n:"api_request_action"`
Version string `json:"version" form:"version" validate:"required,alphanum" label_i18n:"api_request_version"`
}

// 字符串格式:"sys/user:create:v1"
id.String()

JSON RPC body 和 form RPC request 都使用同一组 Identifier 字段。 Identifier.String() 始终格式化为 {resource}:{action}:{version}

Request / Params / Meta

Request

统一的 API 请求结构:

type Request struct {
Identifier
Params Params `json:"params"`
Meta Meta `json:"meta"`
}

如果希望 handler 注入明确从 paramsmeta 解码,请分别在请求参数结构体 中嵌入 api.P,在 metadata 结构体中嵌入 api.M

Params

Params 承载请求的业务数据("做什么"):

type Params map[string]any

// 解码到类型化结构体
var userParams UserParams
err := request.Params.Decode(&userParams)

// 访问单个值
value, exists := request.Params["username"]

Meta

Meta 承载请求元数据("怎么做" — 分页、排序、格式):

type Meta map[string]any

// 解码到类型化结构体
var pageable page.Pageable
err := request.Meta.Decode(&pageable)

// 访问单个值
value, exists := request.Meta["format"]

Params vs Meta

维度ParamsMeta
用途业务数据请求控制
解码目标TParamsTSearchpage.PageableDataOptionConfig
示例usernameemaildepartmentIdpagesizesortformat

认证

AuthConfig

type AuthConfig struct {
Strategy string // "none"、"bearer"、"signature"、"ip" 或自定义
Options map[string]any // 策略特定选项
}

AuthConfig.Clone() 会复制 strategy/options。资源或操作需要调整 auth 但不 想修改共享配置时使用它。

内置认证策略

策略常量说明
无认证api.AuthStrategyNone公开访问
Bearerapi.AuthStrategyBearerBearer 令牌认证
签名api.AuthStrategySignature请求签名认证
IPapi.AuthStrategyIP来源 IP 白名单认证

辅助函数

api.Public() // 策略为 "none" 的 AuthConfig
api.BearerAuth() // 策略为 "bearer" 的 AuthConfig
api.SignatureAuth() // 策略为 "signature" 的 AuthConfig
api.IPAuth() // 策略为 "ip",使用 "default" whitelist
api.IPAuth("ops") // 策略为 "ip",使用 "ops" whitelist

api.IPAuth(...) 接受 0 或 1 个 whitelist 名称。不传时使用 api.DefaultIPWhitelist"default");选中的名称会写入 AuthConfig.Optionsapi.AuthOptionWhitelist。传入多个名称会 panic。 内置 IP strategy 通过 security.IPWhitelistLoader 解析命名列表;默认 loader 读取 vef.security.ip_whitelists。所有认证失败都返回 security.ErrIPNotAllowed,缺失或为空的命名 whitelist 会 fail-closed,而不会 降级为公开访问。位于反向代理之后时,需要配置 vef.app.trusted_proxies,让 Fiber 解析到真实客户端 IP。

自定义认证策略实现 api.AuthStrategy,并通过 vef.ProvideAuthStrategy(...) 注册到 vef:api:auth_strategies

资源级 vs 操作级认证

// 资源级:所有操作使用签名认证
api.NewRPCResource("external/webhook", api.WithAuth(api.SignatureAuth()))

// 操作级:按操作覆盖
crud.NewCreate[User, UserParams]().Public() // 无认证
crud.NewFindPage[User, UserSearch]().RequiredPermission("sys:user:query") // Bearer + 权限

限流

type RateLimitConfig struct {
Max int // 允许的最大请求数
Period time.Duration // 时间窗口
Key string // 自定义限流 key(可选)
}

通过 CRUD builder 使用:

crud.NewCreate[User, UserParams]().RateLimit(100, time.Minute)

内置 rate limiter 使用 sliding window,并按节点独立计数。未声明自己 RateLimit 的 operation 使用 engine 默认值,v0.38 起可由用户配置:

[vef.api.rate_limit]
max = 100 # 省略时的默认值
period = "5m" # 省略时的默认值

显式提供 RateLimitConfigMax <= 0 时,该 operation 不启用限流。框架 默认 key 包含 resource、version、action、解析后的客户端 IP 和 principal ID;匿名请求使用 anonymous principal。

Operation 认证配置由 Operation.Auth 承载;公开 operation 会解析为 api.AuthStrategyNone,受保护 operation 则携带选中的 auth strategy 和 options。

Engine

Engine 管理资源注册和 HTTP 路由:

type Engine interface {
Register(resources ...Resource) error // 添加资源
Lookup(id Identifier) *Operation // 运行时查找操作
Mount(router fiber.Router) error // 挂载到 Fiber 路由器
}

Handler 解析

VEF 通过参数注入支持灵活的 handler 签名:

// 最简 handler
func (r *UserResource) Create(ctx fiber.Ctx) error { ... }

// 自动注入参数
func (r *UserResource) Create(ctx fiber.Ctx, db orm.DB, principal *security.Principal) error { ... }

// 带类型化 params
func (r *UserResource) Create(ctx fiber.Ctx, params UserParams, db orm.DB) error { ... }

参数解析接口

接口用途
HandlerParamResolver运行时从请求上下文解析 handler 参数
FactoryParamResolver启动时解析 handler 参数(依赖注入)
HandlerAdapter将任意 handler 签名转换为 fiber.Handler
HandlerResolver在资源上查找 handler 函数

RouterStrategy 也是公开扩展点,用于自定义 HTTP 暴露方式。strategy 声明 自己能处理哪些 api.Kind,在 Setup 中接收 Fiber router,并在 Route 中注册每个已解析操作。

错误类型

错误含义
ErrEmptyResourceName资源名称为空
ErrInvalidResourceName资源名称不符合命名规则
ErrResourceNameSlash资源名称以 / 开头或结尾
ErrResourceNameDoubleSlash资源名称包含 //
ErrInvalidResourceKind无效的资源类型值
ErrInvalidVersionFormat版本不匹配 v\d+ 格式
ErrEmptyActionNameAction 名称为空
ErrInvalidActionNameAction 不符合类型特定规则
ErrInvalidParamsTypeParams.Decode 目标不是指向结构体的指针
ErrInvalidMetaTypeMeta.Decode 目标不是指向结构体的指针

Params.DecodeMeta.Decode 都要求传入 struct 指针。其他目标会返回 ErrInvalidParamsTypeErrInvalidMetaType

ErrInvalidRequestParamsErrInvalidRequestMeta 使用 result.ErrCodeBadRequest1400)和 HTTP status 400。RPC form 的 params/meta JSON 或 REST JSON body 解析失败时会返回它们。

api 包的其余公开接口面——版本常量、请求 header、审计事件、认证策略 registry、operation 收集类型、请求 helper 与 handler/router 扩展接口——在 公开 API 索引中逐符号收录。

下一步