如何在NestJS中优先开发GraphQL并同时提供GraphQL和REST接口
实现方案
NestJS 官方 GraphQL 模块已经暴露了内部执行核心,你不需要额外启动HTTP请求调用GraphQL接口,直接在REST控制器内调用执行器即可,完全复用已有resolver逻辑,同时可以透传所有请求头信息。
前置准备
确保你已经正常配置了@nestjs/graphql模块,GraphQL相关的resolver、schema均已开发完成可正常运行。
步骤1:导入依赖
import { Controller, Get, Query, Req, HttpException, HttpStatus } from '@nestjs/common'; import { GraphQLSchemaHost } from '@nestjs/graphql'; import { parse, execute } from 'graphql'; import { Request } from 'express'; // 用Fastify的话替换为对应Request类型
步骤2:注入依赖并编写接口逻辑
@Controller('api') export class ApiController { constructor(private readonly gqlSchemaHost: GraphQLSchemaHost) {} @Get('classes') async getClassesByYear(@Query('year') year: number, @Req() req: Request) { const { schema } = this.gqlSchemaHost; // 构造GraphQL查询文档 const queryDocument = parse(` query GetClasses($year: Int!) { classes(year: $year) { courseId name teacher { firstName lastName } credit prerequisite { courseId name } } } `); // 执行GraphQL查询,透传当前请求作为上下文,保留所有头信息 const executeResult = await execute({ schema: schema, document: queryDocument, variableValues: { year }, contextValue: req, // 如果你的GraphQL上下文有自定义封装,此处保持和自定义的上下文结构一致即可 }); // 处理执行错误 if (executeResult.errors) { throw new HttpException( { errors: executeResult.errors.map(err => err.message) }, HttpStatus.BAD_REQUEST ); } return executeResult.data?.classes; } }
可选简化方案(Apollo驱动适用)
如果你用的是Apollo作为GraphQL的运行时,可以直接注入ApolloServer实例,调用executeOperation方法,代码更简洁:
// 注入ApolloServer实例 constructor(@Inject(ApolloServer) private readonly apolloServer: ApolloServer) {} // 接口内执行逻辑 const result = await this.apolloServer.executeOperation( { query: `query GetClasses($year: Int!) { classes(year: $year) { courseId, name, ... } }`, variables: { year } }, { contextValue: req } );
注意事项
- 所有GraphQL resolver里能拿到的上下文信息,包括请求头、用户认证信息等,都会和直接调用GraphQL接口完全一致
- 对于Mutation操作,对应REST的POST/PUT/DELETE接口,只需要把查询语句替换为mutation语句即可,执行逻辑完全相同
- 可以把常用的GraphQL查询语句抽成常量统一维护,也可以封装通用执行工具函数,减少重复代码
内容的提问来源于stack exchange,提问作者Tianzhen Lin
相关产品推荐
相关产品推荐

