【问题标题】:Apollo Server & 4xx status codesApollo Server & 4xx 状态码
【发布时间】:2020-02-23 11:05:45
【问题描述】:

目前,我的 Apollo 服务器(在 HapiJS 上运行)为每个请求返回 HTTP 200,包括失败的请求。

我希望 GraphQL 服务器针对不成功的请求返回 HTTP 4xx。主要原因是我想为我的 ELB 设置监控。

我知道 Apollo Server 有一个引擎平台,但我想使用我当前的基础架构来实现它。

我有什么想法可以做到这一点吗?我试图为我的 HapiJS 服务器捕获“onPreResponse”事件,但我无法在那里修改状态代码。

【问题讨论】:

    标签: hapijs apollo-server


    【解决方案1】:

    读完这个answer。这里通过修改hapiApollo.ts文件的hapijs插件graphqlHapi来解决。

    server.ts:

    import { makeExecutableSchema } from 'apollo-server';
    import { ApolloServer, gql } from 'apollo-server-hapi';
    import Hapi from 'hapi';
    import { graphqlHapi } from './hapiApollo';
    
    const typeDefs = gql`
      type Query {
        _: String
      }
    `;
    const resolvers = {
      Query: {
        _: () => {
          throw new Error('some error');
        },
      },
    };
    const schema = makeExecutableSchema({ typeDefs, resolvers });
    const port = 3000;
    async function StartServer() {
      const app = new Hapi.Server({ port });
      graphqlHapi.register(app, { path: '/graphql', graphqlOptions: { schema } });
      app.ext('onPreResponse', (request: any, h: any) => {
        const response = request.response;
        if (!response.isBoom) {
          return h.continue;
        }
        return h.response({ message: response.message }).code(400);
      });
    
      await app.start();
    }
    
    StartServer()
      .then(() => {
        console.log(`apollo server is listening on http://localhost:${port}/graphql`);
      })
      .catch((error) => console.log(error));
    

    hapiApollo.ts:

    import Boom from 'boom';
    import { Server, Request, RouteOptions } from 'hapi';
    import { GraphQLOptions, runHttpQuery, convertNodeHttpToRequest } from 'apollo-server-core';
    import { ValueOrPromise } from 'apollo-server-types';
    
    export interface IRegister {
      (server: Server, options: any, next?: Function): void;
    }
    
    export interface IPlugin {
      name: string;
      version?: string;
      register: IRegister;
    }
    
    export interface HapiOptionsFunction {
      (request?: Request): ValueOrPromise<GraphQLOptions>;
    }
    
    export interface HapiPluginOptions {
      path: string;
      vhost?: string;
      route?: RouteOptions;
      graphqlOptions: GraphQLOptions | HapiOptionsFunction;
    }
    
    const graphqlHapi: IPlugin = {
      name: 'graphql',
      register: (server: Server, options: HapiPluginOptions, next?: Function) => {
        if (!options || !options.graphqlOptions) {
          throw new Error('Apollo Server requires options.');
        }
        server.route({
          method: ['GET', 'POST'],
          path: options.path || '/graphql',
          vhost: options.vhost || undefined,
          options: options.route || {},
          handler: async (request, h) => {
            try {
              const { graphqlResponse, responseInit } = await runHttpQuery([request, h], {
                method: request.method.toUpperCase(),
                options: options.graphqlOptions,
                query:
                  request.method === 'post'
                    ? // TODO type payload as string or Record
                      (request.payload as any)
                    : request.query,
                request: convertNodeHttpToRequest(request.raw.req),
              });
    
              // add our custom error handle logic
              const graphqlResponseObj = JSON.parse(graphqlResponse);
              if (graphqlResponseObj.errors && graphqlResponseObj.errors.length) {
                throw new Error(graphqlResponseObj.errors[0].message);
              }
    
              const response = h.response(graphqlResponse);
              Object.keys(responseInit.headers as any).forEach((key) =>
                response.header(key, (responseInit.headers as any)[key]),
              );
              return response;
            } catch (error) {
              // handle our custom error
              if (!error.name) {
                throw Boom.badRequest(error.message);
              }
    
              if ('HttpQueryError' !== error.name) {
                throw Boom.boomify(error);
              }
    
              if (true === error.isGraphQLError) {
                const response = h.response(error.message);
                response.code(error.statusCode);
                response.type('application/json');
                return response;
              }
    
              const err = new Boom(error.message, { statusCode: error.statusCode });
              if (error.headers) {
                Object.keys(error.headers).forEach((header) => {
                  err.output.headers[header] = error.headers[header];
                });
              }
              // Boom hides the error when status code is 500
              err.output.payload.message = error.message;
              throw err;
            }
          },
        });
    
        if (next) {
          next();
        }
      },
    };
    
    export { graphqlHapi };
    

    现在,当 GraphQL 解析器抛出错误时,客户端将收到带有 Http 状态码 400 的自定义响应,而不是带有 GraphQL 错误响应的 200 状态码。

    常规来自浏览器:

    Request URL: http://localhost:3000/graphql
    Request Method: POST
    Status Code: 400 Bad Request
    Remote Address: 127.0.0.1:3000
    Referrer Policy: no-referrer-when-downgrade
    

    响应正文为:{"message":"some error"}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-05
      • 1970-01-01
      • 2011-11-10
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 2019-08-13
      相关资源
      最近更新 更多