在 Modern.js 应用中,开发者可以在 api/lambda
目录下定义接口文件,并导出接口函数。在前端代码中,可以用文件引用的方式,直接调用这些接口函数,发起接口请求。
这种调用方式我们称为一体化调用,开发者无需编写前后端胶水层代码,并天然地保证前后端类型安全。
new
命令:目前推荐使用框架模式创建 BFF,后续我们将会移除 BFF 类型的概念。
modern.config.[tj]s
中:允许使用一体化调用的函数,我们称为 BFF 函数。这里写一个最简单的 BFF 函数,首先创建 api/lambda/hello.ts
文件:
接着在 src/routes/page.tsx
中直接引入函数并调用:
在调用 new
命令后,Modern.js 生成器会自动在 tsconfig.json
中配置 @api
别名,因此可以直接通过别名的方式引入函数。
在 src/routes/page.tsx
中引入的函数,会自动转换成接口调用,不需要再通过请求 SDK 或 Web Fetch 调用接口。
执行 pnpm run dev
后,打开 http://localhost:8080/
可以看到页面已经展示了 BFF 函数返回的内容,在 Network 中可以看到页面向 http://localhost:8080/api/hello
发送了请求:
Modern.js 中,BFF 函数对应的路由系统是基于文件系统实现的,也是一种约定式路由。api/lambda
下的所有文件中的每个 BFF 函数都会映射为一个接口,下面介绍几种路由的约定。
所有 BFF 函数生成的路由都带有统一的前缀,默认值为 /api
。可以通过 bff.prefix 设置公共路由的前缀。
以 index.[jt]s
命名的文件会被映射到上一层目录。
api/lambda/index.ts
-> {prefix}/
api/lambda/user/index.ts
-> {prefix}/user
支持解析嵌套的文件,如果创建嵌套文件夹结构,文件仍会以相同方式自动解析路由。
api/lambda/hello.ts
-> {prefix}/hello
api/lambda/user/list.ts
-> {prefix}/user/list
同样的,创建命名带有 [xxx]
的文件夹或者文件,支持动态的命名路由参数。动态路由的函数参数规则可以看 dynamac-path。
api/lambda/user/[username]/info.ts
-> {prefix}/user/:username/info
api/lambda/user/username/[action].ts
-> {prefix}/user/username/:action
默认 api/lambda/
目录下所有文件都会当作 BFF 函数文件去解析,但以下文件不会被解析:
_
开头的文件。例如:_utils.ts
。_
开头的文件夹下所有文件。例如:_utils/index.ts
、_utils/cp.ts
。foo.test.ts
。hello.d.ts
。node_module
下的文件。Modern.js 的 BFF 函数需要遵循 RESTful API 标准来定义,开发者需要按照一系列规则来定义 BFF 函数。
BFF 函数不仅会在项目中被调用,也应该允许其他项目通过请求 SDK 或 Web fetch 调用。因此 Modern.js 没有在一体化调用时定义私有协议,而是通过标准的 HTTP Method,以及 params
、query
、body
等通用的 HTTP 请求参数来定义函数。
Modern.js BFF 函数的导出名决定了函数对应接口的 HTTP Method,如 get
,post
等。例如导出一个 GET 接口:
按照以下例子,则可导出一个 POST
接口:
对应 HTTP Method,Modern.js 也支持了 9 种定义,即:GET
、POST
、PUT
、DELETE
、CONNECT
、TRACE
、PATCH
、OPTIONS
、HEAD
,即可以用这些 Method 作为函数导出的名字。
名字是大小不敏感的,如果是 GET
,写成 get
、Get
、GEt
、GET
,都可以准确识别。而默认导出,即 export default xxx
则会被映射为 Get
。
Modern.js 推荐将 BFF 函数定义为 Async 异步函数,即使函数中不存在异步流程,例如:
这是因为在前端调用时,BFF 函数会自动转换成 HTTP 接口调用,而 HTTP 接口调用时异步的,在前端通常会这样使用:
因此,为了保持类型定义与实际调用体验统一,我们推荐在定义 BFF 函数时将它设置为异步函数。
函数参数规则分为两块,分别是请求路径中的动态路由(Dynamic Path)和请求选项(RequestOption)。
动态路由会作为 BFF 函数第一部分的入参,每个入参对应一段动态路由。例如以下示例,level
和 id
会作为前两个参数传递到函数中:
在调用时直接传入动态参数:
Dynamic Path 之后的参数是包含 querystring、request body 的对象 RequestOption
,这个字段用来定义 data
和 query
的类型。
在不存在动态路由的普通函数中,可以从第一个入参中获取传入的 data
和 query
,例如:
这里你也可以使用自定义类型:
当函数文件使用动态路由规则时,动态路由会在 RequestOption
对象参数前。
调用时也按照函数定义,传入对应的参数即可:
普通的 BFF 函数写法有时并不能满足需求,我们正在设计一套更强大的 BFF 函数写法,让开发者更方便地扩展 BFF 函数。
敬请期待