将GraphQL Schema暴露为REST API的实现方案及NestJS相关包有哪些?
可替代Sofa的NestJS/GraphQL生态方案及实现方式
以下方案均可以实现复用现有GraphQL业务逻辑暴露REST端点的需求:
1. NestJS原生无第三方依赖方案(最推荐,无额外包引入成本)
不需要引入任何额外开源包,完全基于NestJS本身的依赖注入能力复用业务逻辑:
- 方式一:直接调用GraphQL Resolver方法
你编写的GraphQL Resolver本身就是Nest可注入的Provider,直接在REST Controller中注入对应Resolver实例,调用目标业务方法即可,完全绕开GraphQL的解析、验证执行流程,性能最优
示例代码:// 现有GraphQL Resolver @Resolver() export class UserResolver { @Query() async getUser(@Args('id') id: string) { // 已有的业务逻辑 return userService.findById(id); } } // 新增REST Controller @Controller('rest/users') export class UserRestController { // 直接注入现有Resolver constructor(private readonly userResolver: UserResolver) {} @Get(':id') async getRestUser(@Param('id') id: string) { // 直接复用Resolver的业务方法 return this.userResolver.getUser(id); } } - 方式二:通过GraphQL执行器复用完整执行链路
如果需要保留GraphQL的参数校验、权限校验、中间件等完整执行逻辑,可以注入GraphQLExecutorService执行GraphQL请求
示例代码:import { GraphQLExecutorService } from '@nestjs/graphql'; @Controller('rest/users') export class UserRestController { constructor(private readonly gqlExecutor: GraphQLExecutorService) {} @Get(':id') async getRestUser(@Param('id') id: string) { const result = await this.gqlExecutor.execute({ query: `query GetUser($id: ID!) { getUser(id: $id) { id name email } }`, variables: { id } }); return result.data.getUser; } }
2. 第三方开源包方案
除了Sofa之外,生态内还有两类成熟开源包可选用:
graphql2rest:GraphQL生态通用的转换工具,支持基于Schema生成完整的REST接口映射,支持自定义HTTP方法、路径、返回字段过滤。集成到NestJS只需要在初始化时传入你的GraphQL Schema实例,在Controller中调用转换方法处理REST请求即可nestjs-graphql-to-rest:专门针对NestJS封装的工具包,支持通过装饰器或者配置文件批量指定需要暴露为REST接口的Query/Mutation,自动完成参数映射、请求转换,不需要手动编写每个Controller的调用逻辑
3. 网关层转换方案(适合微服务架构)
如果你的服务已经接入API网关,可以直接在网关层配置REST到GraphQL的映射规则,完全不需要修改现有GraphQL服务的代码:
- 网关收到REST请求后,根据预设规则拼接对应的GraphQL查询语句、提取变量
- 网关将拼接好的GraphQL请求转发到现有GraphQL服务
- 网关收到GraphQL返回结果后,直接返回给REST调用方
适用场景参考:小项目优先选原生调用Resolver的方案,改动最小性能最高;需要批量暴露大量REST端点选第三方包方案;微服务架构不想改动业务服务代码选网关方案。
内容的提问来源于stack exchange,提问作者Arocks
相关产品推荐
相关产品推荐

