Javascript GraphQL-如何使用不同的状态代码进行响应?

Javascript GraphQL-如何使用不同的状态代码进行响应?,javascript,graphql,apollo,react-apollo,Javascript,Graphql,Apollo,React Apollo,我的Graphql和Apollo客户端有问题 我总是在使用REST时创建不同的响应,比如401代码,但在这里我不知道如何做类似的行为 当我得到响应时,我希望它转到catch函数。 我的前端代码示例如下: client.query({ query: gql` query TodoApp { todos { id text completed } } `, }) .then(data => co

我的Graphql和Apollo客户端有问题

我总是在使用REST时创建不同的响应,比如401代码,但在这里我不知道如何做类似的行为

当我得到响应时,我希望它转到catch函数。 我的前端代码示例如下:

client.query({
  query: gql`
    query TodoApp {
      todos {
        id
        text
        completed
      }
    }
  `,
})
  .then(data => console.log(data))
  .catch(error => console.error(error));

有人能帮我吗?

在GraphQL(至少在GraphQL js中)中返回错误的方法是在resolve函数中抛出错误。由于HTTP状态代码特定于HTTP传输,而GraphQL不关心传输,因此无法在那里设置状态代码。您可以改为在resolve函数中抛出特定错误:

age: (person, args) => {
  try {
    return fetchAge(person.id);
  } catch (e) {
    throw new Error("Could not connect to age service");
  }
}
GraphQL错误会在响应中发送到客户端,如下所示:

{
  "data": {
    "name": "John",
    "age": null
  },
  "errors": [
    { "message": "Could not connect to age service" }
  ]
}
如果消息没有足够的信息,您可以为GraphQL服务器创建一个特殊的错误类,其中包含一个状态代码。为了确保状态代码包含在响应中,您必须在创建中间件时指定
formatError
函数:

app.use('/graphql', bodyParser.json(), graphqlExpress({ 
    schema: myGraphQLSchema,
    formatError: (err) => ({ message: err.message, status: err.status }),
}));

最近增加了一项有关错误的输出:

GraphQL服务可能会使用键扩展提供额外的错误条目。如果设置了此条目,则其值必须为map。这个条目是为实现者保留的,他们可以在他们认为合适的情况下向错误添加额外的信息,并且对其内容没有额外的限制

现在,使用
extensions
字段,您可以为
错误
条目自定义机器可读信息:

{
  "errors": [
    {
      "message": "Name for character with ID 1002 could not be fetched.",
      "locations": [ { "line": 6, "column": 7 } ],
      "path": [ "hero", "heroFriends", 1, "name" ],
      "extensions": {
        "code": "CAN_NOT_FETCH_BY_ID",
        "timestamp": "Fri Feb 9 14:33:09 UTC 2018"
      }
    }
  ]
}

最新版本的规范符合此功能。请查看。

作为Glenn答案的补充,是Graphql规范的一部分,它定义了如何处理错误。因此,要知道请求是否失败(或部分失败),您可以检查响应根目录下的“errors”键。

在尝试了一段时间后,我意识到缺少一些重要的细节。主要是,如果您有一个带有自定义字段的自定义错误对象,则上面的示例将允许您读取自定义属性,因为自定义错误似乎被强制转换到只有消息属性的标准
error
对象中

下面是我的
formatError
函数的外观(请注意
originalError
属性):

originalError
属性似乎总是设置好的,但作为一种保护措施,您可以使用lodash
get
属性

我有一个定义的自定义错误类,名为
apierro

class APIError extends Error {
  constructor({ code, message }) {
    const fullMsg = `${code}: ${message}`;

    super(fullMsg);
    this.code = code;
    this.message = message;
  }
}

export default APIError;
在我的解析器中,我抛出如下异常:

  const e = new APIError({
    code: 500,
    message: 'Internal server error'
  });

我认为关于graphql和错误的讨论中缺少的一个关注点是从http到gql的转换中的错误,而这正是401应该出现的地方

在转换请求时,您应该将授权头(或您正在使用的任何身份验证方法)转换为用户,如果无法对其进行身份验证,则应返回HTTP 401错误-这不是图形或api规范的一部分,只是用户是否可以验证的问题。您甚至不必检查查询

另一方面,403错误最有可能发生在gql层(并且可能不会使用http状态代码,但这是另一个讨论),因为它可能是非常特定于域的,您必须知道查询以决定它是否被禁止

HTTP403状态可以用来告诉用户他根本无法访问GQLAPI


在express/nestjs中,我们通过在到达graphql层之前使用一个中间件来解决这个问题,该层通过用户(可能未定义)来丰富请求,或者如果用户无法通过身份验证,则请求将失败。如果您不提供凭证(或类似的凭证),我认为401不应该被返回。

谢谢helfer,它非常有用。
formatError`已被弃用,并被“customFormatErrorFn”取代。它将在1.0.0版中删除。
非常有用!
  const e = new APIError({
    code: 500,
    message: 'Internal server error'
  });