如何在 GraphQL 中设置 http 状态码

Str*_*ch0 3 http-status-codes koa graphql apollo-server

I want to set an http status code in my GraphQL authentication query, depending on if auth attempt was successful (200), unauthorised (401) or missing parameters (422).

I am using Koa and Apollo and have configured my server like so:

const graphqlKoaMiddleware = graphqlKoa(ctx => {
  return ({
    schema,
    formatError: (err) => ({ message: err.message, status: err.status }),
    context: {
      stationConnector: new StationConnector(),
      passengerTypeConnector: new PassengerTypeConnector(),
      authConnector: new AuthConnector(),
      cookies: ctx.cookies
    }
  })
})

router.post("/graphql", graphqlKoaMiddleware)
Run Code Online (Sandbox Code Playgroud)

As you can see, I have set my formatError to return a message and status but currently only the message is getting returned. The error message comes from the error that I throw in my resolver function.

For example:

const resolvers = {
  Query: {
    me: async (obj, {username, password}, ctx) => {
      try {
        return await ctx.authConnector.getUser(ctx.cookies)  
      }catch(err){
        throw new Error(`Could not get user: ${err}`);
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

My only issue with this method is it is setting the status code in the error message and not actually updating the response object.

Does GraphQL require a 200 response even for failed queries / mutations or can I some how update the response objects status code? If not, How do I set the aforementioned error object status code?

Dan*_*den 6

除非 GraphQL 请求本身格式错误,否则 GraphQL 将返回 200 状态代码,即使在其中一个解析器中抛出错误也是如此。这是设计使然,所以没有真正的方法来配置 Apollo 服务器来改变这种行为。

也就是说,您可以轻松连接自己的中间件。您可以导入runHttpQueryApollo 中间件在后台使用的函数。实际上,您几乎可以复制源代码并对其进行修改以满足您的需要:

const graphqlMiddleware = options => {
  return (req, res, next) => {
    runHttpQuery([req, res], {
      method: req.method,
      options: options,
      query: req.method === 'POST' ? req.body : req.query,
    }).then((gqlResponse) => {
      res.setHeader('Content-Type', 'application/json')

      // parse the response for errors and set status code if needed

      res.write(gqlResponse)
      res.end()
      next()
    }, (error) => {
      if ( 'HttpQueryError' !== error.name ) {
        return next(error)
      }

      if ( error.headers ) {
        Object.keys(error.headers).forEach((header) => {
          res.setHeader(header, error.headers[header])
        })
      }

      res.statusCode = error.statusCode
      res.write(error.message)
      res.end()
      next(false)
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 如何使用你们提供的中间件? (2认同)