2026/9/14 6:04:40

Wasp 0.12 自定义 HTTP API 端点完全指南:从 api 声明到中间件与实体注入

Wasp 0.12 自定义 HTTP API 端点完全指南:从 api 声明到中间件与实体注入 Wasp 0.12 自定义 HTTP API 端点完全指南从 api 声明到中间件与实体注入【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/waspWasp 中默认的前后端交互机制是 OperationsQuery / Action它会自动生成 RPC 式客户端辅助函数如useQuery。但当你需要精确控制 URL 的 method/path例如第三方回调地址POST /webhook/callback或自定义响应内容时Operations 就显得不够灵活。本文基于 Wasp 0.12 版本文档系统讲解api声明的完整用法如何在.wasp文件中声明路由、如何编写 Node.jsExpress 风格实现、如何从客户端和外部世界调用、如何解决 CORS、如何注入 Entity 与鉴权并结合仓库源码说明 Wasp 编译器在底层的代码生成机制。什么是 Wasp 的 API在 Wasp 中api用于把一段 JavaScript/TypeScript 函数绑定到某个具体的 HTTP 端点例如POST /something/special。它与 Operations 有本质区别Operations 通过 Wasp 的 RPC 通道通信会生成客户端辅助函数useQuery、useAction等api没有客户端辅助函数它暴露的是裸 HTTP 端点客户端需要直接通过 HTTP 请求调用外部世界浏览器、curl、Postman、其他 Web 服务也可以直接访问。从源码看API 的声明模型定义在 waspc/src/Wasp/AppSpec/Api.hs 中Api记录类型包含五个字段data Api Api { fn :: ExtImport, -- NodeJS 实现导入 middlewareConfigFn :: Maybe ExtImport, -- 可选中间件配置函数 entities :: Maybe [Ref Entity], -- 可选实体列表 httpRoute :: (HttpMethod, String), -- (方法, 路径)如 (GET, /foo/bar) auth :: Maybe Bool -- 是否解析 JWT 鉴权 }其中HttpMethod枚举为ALL | GET | POST | PUT | DELETE见 Api.hs这也是api声明支持的全部 HTTP 方法。创建 Wasp API 只需两步在 Wasp 文件中用api声明路由定义 API 对应的 Node.js 实现。两步完成后即可从客户端代码通过wasp/client/api提供的 Axios 包装器或从外部世界调用该 API。声明 API 路由在main.wasp中使用api声明将实现函数与 (method, path) 绑定// ... api fooBar { // API 及其实现不必但可以同名 fn: import { fooBar } from src/apis, httpRoute: (GET, /foo/bar) }关键点fn指向实现函数的导入路径src别名指向项目的src目录httpRoute是(HttpMethod, string)二元组方法可取ALL、GET、POST、PUT、DELETE路径是标准的 Express 路径字符串支持:param、*等 Express 语法。TypeScript 项目注意先声明、保持wasp start运行如果使用 TypeScript为了让 Wasp 编译器为 API 生成类型即wasp/server/api中导出的实现类型应先把api声明写入.wasp文件并保持wasp start命令运行。编译器会在后台持续生成类型之后你在实现文件里才能拿到带类型的FooBar。编写 API 的 Node.js 实现实现是一个接收三个参数的 Node.js 函数reqExpress 的 Request 对象resExpress 的 Response 对象context由 Wasp注入的附加上下文对象包含用户会话信息以及实体Entities信息。简单示例中暂不使用详见后文「在 API 中使用 Entities」。JavaScript 版本src/apis.jsexport const fooBar (req, res, context) { res.set(Access-Control-Allow-Origin, *); // 示例修改响应头以覆盖 Wasp 默认 CORS 中间件 res.json({ msg: Hello, ${context.user ? registered user : stranger}! }); };TypeScript 版本src/apis.tsimport { FooBar } from wasp/server/api; // 此类型由 Wasp 根据上面的 api 声明生成 export const fooBar: FooBar (req, res, context) { res.set(Access-Control-Allow-Origin, *); // 示例修改响应头以覆盖 Wasp 默认 CORS 中间件 res.json({ msg: Hello, ${context.user ? registered user : stranger}! }); };注意上面示例修改了Access-Control-Allow-Origin响应头——这展示了如何用res.set覆盖 Wasp 默认的 CORS 行为是自定义 API 中常见的实操手法。为 API 提供额外类型信息TypeScript假设我们要创建一个GET路由从路径参数接收一个 email 地址并返回生命、宇宙以及一切问题的答案42。在 Wasp 中定义带路径参数的路由api fooBar { fn: import { fooBar } from src/apis, entities: [Task], httpRoute: (GET, /foo/bar/:email) }然后在实现中使用FooBar的泛型参数第一个泛型是params路径参数类型第二个泛型是response类型即可获得全链路类型安全import { FooBar } from wasp/server/api; export const fooBar: FooBar { email: string }, // params { answer: number } // response (req, res, _context) { console.log(req.params.email); res.json({ answer: 42 }); };req.params.email会按声明类型被推断为string编译器与编辑器会替你检查 params 与 response 的取值是否符合契约。调用 API从外部世界调用外部调用只需按声明的 method 和 path 直接请求即可。例如应用运行在https://example.com则可对https://example.com/foo/callback发起GET请求浏览器、Postman、curl、其他 Web 服务均可。从客户端调用从客户端调用含鉴权支持时从wasp/client/api导入 Axios 包装器并发起请求import React, { useEffect } from react; import { api } from wasp/client/api; async function fetchCustomRoute() { const res await api.get(/foo/bar); console.log(res.data); } export const Foo () { useEffect(() { fetchCustomRoute(); }, []); return // .../; };该包装器已预先配置好 API 基础地址、认证自动附带 JWT与错误处理因此api.get(/foo/bar)会携带用户凭证。确保 CORS 生效自定义 API 被设计得尽可能灵活因此不会像 Operations 那样自动套用默认中间件。要在客户端使用这些 API必须确保 CORS跨域资源共享已开启——方法是在 Wasp 文件中为 API 定义自定义中间件。apiNamespace就是一种简单的声明用于把某个middlewareConfigFn应用到指定路径下的所有APIapiNamespace fooBar { middlewareConfigFn: import { fooBarNamespaceMiddlewareFn } from src/apis, path: /foo }实现文件JavaScript返回默认配置export const apiMiddleware (config) { return config; };TypeScript 版本import { MiddlewareConfigFn } from wasp/server; export const apiMiddleware: MiddlewareConfigFn (config) { return config; };这里返回的是默认中间件配置Wasp 据此为/foo路径下的所有 API 启用 CORS。关于中间件配置的更多细节参见 Middleware Configuration。源码视角middlewareConfigFn的产物是 Express 中间件。从生成模板 waspc/data/Generator/templates/server/src/routes/apis/index.ts 可以看到每个 API 路由实际生成的是router.get(/foo/bar, [auth, ...middleware], defineHandler(...))而apiNamespace会生成router.use(/foo, globalMiddlewareConfigForExpress(namespaceMiddlewareConfigFn))——即按路径前缀批量挂载中间件这就是 CORS 能作用于整条路径下所有 API 的底层原因。在 API 中使用 Entities很多场景下API 中要访问的资源是 Wasp 的 Entities。要在一个 API 中使用 Entity只需把它加进api声明的entities列表api fooBar { fn: import { fooBar } from src/apis, entities: [Task], httpRoute: (GET, /foo/bar) }Wasp 会把声明的 Entity 注入 API 的context参数让你直接拿到该 Entity 的 Prisma APIexport const fooBar (req, res, context) { res.json({ count: await context.entities.Task.count() }); };TypeScript 版本import { FooBar } from wasp/server/api; export const fooBar: FooBar (req, res, context) { res.json({ count: await context.entities.Task.count() }); };context.entities.Task暴露的就是 Prisma 的prisma.taskPrisma Client 的 CRUD API 句柄因此你可以调用count()、findMany()、create()等全部 Prisma 方法。源码视角注入逻辑在生成模板中体现得很直接见 routes/apis/index.ts编译器为每个 API 生成context { user, entities: { Task: prisma.task, ... } }再调用你的实现函数。实体对象的组装由 waspc/src/Wasp/Generator/ServerGenerator/ApiRoutesG.hs 中的getApiEntitiesObject完成它把声明中的实体引用映射为prisma.prismaIdentifier。API 参考api 声明支持的字段一个完整的api声明示例api fooBar { fn: import { fooBar } from src/apis, httpRoute: (GET, /foo/bar), entities: [Task], auth: true, middlewareConfigFn: import { apiMiddleware } from src/apis }各字段说明字段必需说明fn: ExtImport✅API 的 Node.js 实现导入语句httpRoute: (HttpMethod, string)✅HTTP方法, 路径对。方法可选ALL、GET、POST、PUT、DELETE路径为 Express 路径字符串entities: [Entity]❌希望在 API 内部使用的实体列表见「在 API 中使用 Entities」auth: bool❌若项目启用了 auth默认值为true会提供context.user对象如果不想解析 Authorization Header 中的 JWT请设为falsemiddlewareConfigFn: ExtImport❌该 API 的 Express 中间件配置函数导入详见 middleware-config 文档关于auth字段的源码细节auth的默认行为与项目全局鉴权状态联动。从 ApiRoutesG.hs 的实现看isAuthEnabledForApi spec api fromMaybe (isAuthEnabled spec) (Api.auth api)即如果api声明里没写auth则继承项目全局的 auth 开关只有显式设置时才覆盖默认值。当auth生效时生成代码会在路由上挂载auth中间件并把context.user通过makeAuthUserIfPossible注入见 routes/apis/index.ts。所以如果某个公开回调接口不应尝试解析 JWT例如 webhook 或公开的计数接口记得显式设置auth: false。总结Wasp 0.12 的api机制为 Operations 之外的定制化 HTTP 需求提供了干净统一的出口两步创建.wasp中声明api 编写三参数req、res、context实现函数灵活路由支持GET/POST/PUT/DELETE/ALL与 Express 路径语法含:param类型安全TS通过生成的FooBar泛型类型约束 params 与 response实体与鉴权注入entities列表注入 Prisma 句柄auth控制 JWT 解析与context.userCORS 与中间件利用apiNamespacemiddlewareConfigFn为整条路径下的 API 统一启用 CORS 或自定义 Express 中间件。从源码层看这些声明最终都会被编译器ApiRoutesG.hs翻译成标准的 Express Router 代码并写入生成项目的src/routes/apis/index.ts因此任何熟悉 Express 的开发者都能快速理解其行为也保证了与 Wasp 生态之外的既有 HTTP 工具链curl、Postman、Webhooks的无缝互通。【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考