【问题标题】:What should be the GraphQL mutation return type when there is no data to return?当没有数据返回时,GraphQL 变异返回类型应该是什么?
【发布时间】:2026-01-05 11:50:02
【问题描述】:

我有一个 Apollo GraphQL 服务器,并且我有一个删除记录的突变。此突变接收资源的 UUID,调用 REST(Ruby on Rails)API,当删除成功时,该 API 仅返回成功的 HTTP 代码和空正文(204 No Content)以及带有错误的 HTTP 错误代码删除不起作用时的消息(404 或 500,典型的 REST 删除端点)。

在定义 GraphQL 突变时,我必须定义突变返回类型。变异返回类型应该是什么?

input QueueInput {
  "The queue uuid"
  uuid: String!
}


deleteQueue(input: QueueInput!): ????????

我可以让它与几种不同类型的返回(布尔、字符串、...)一起使用,但我想知道最佳实践是什么,因为我尝试过的返回类型都没有感觉正确。我认为重要的是,在调用突变后,在客户端我有一些关于如果事情进展顺利(API 返回 204 不是内容)或发生错误(API 返回 404 或 500)会发生什么的信息,并且理想情况下有一些关于错误。

【问题讨论】:

    标签: javascript rest graphql apollo apollo-server


    【解决方案1】:

    GraphQL 中的字段必须始终具有类型。 GraphQL 有null 的概念,但 null 本身并不是一个类型——它只是表示缺乏价值。

    GraphQL 中没有“void”类型。但是,默认情况下类型可以为空,因此无论字段的类型如何,您的解析器都不会返回任何内容,并且该字段将简单地解析为 null。所以你可以

    type Mutation {
      deleteQueue(input: QueueInput!): Boolean #or any other type
    }
    

    或者如果你想要一个专门表示null的标量,你可以create your own

    const { GraphQLScalarType } = require('graphql')
    
    const Void = new GraphQLScalarType({
      description: 'Void custom scalar',
      name: 'Void',
      parseLiteral: (ast) => null,
      parseValue: (value) => null,
      serialize: (value) => null,
    })
    

    然后做

    type Mutation {
      deleteQueue(input: QueueInput!): Void
    }
    

    也就是说,通常的做法是返回 something。对于删除,通常返回已删除的项目或至少返回其 ID。这有助于客户端的缓存管理。返回某种突变负载类型以更好地封装客户端错误也变得越来越普遍。

    您可以在“有效负载”类型中包含任意数量的字段,如下所示:

    type Mutation {
      deleteQueue(input: QueueInput!): DeleteQueuePayload
    }
    
    type DeleteQueuePayload {
      # the id of the deleted queue
      queueId: ID
    
      # the queue itself
      queue: Queue
    
      # a status string
      status: String
    
      # or a status code
      status: Int
    
      # or even an enum
      status: Status
    
      # or just include the client error
      # with an appropriate code, internationalized message, etc.
      error: ClientError
    
      # or an array of errors, if you want to support validation, for example
      errors: [ClientError!]!
    }
    

    DeleteQueuePayload 甚至可以是不同类型的联合,使客户端能够使用__typename 来确定突变的结果。

    但是,您公开哪些信息取决于您的具体需求,而您采用的具体模式归结为意见。

    有关更多讨论和示例,请参阅 herehere

    【讨论】:

    • 嗨丹尼尔!感谢您的回答!是的,我同意返回 null 或 void 是一种选择,但在这种情况下,我不知道 API 中发生了什么,这意味着突变是否成功(http 204)或不成功(http 404、500)。我认为返回一些可以让我向客户提供良好反馈的东西很重要,例如可以在 FE 中用于显示一些错误消息的东西。
    • 返回一个布尔值解决了知道它是否成功的问题,但我认为字符串可能更好。我可以返回“ok”或资源“ID”(如您所建议的),如果出现错误,我可以返回错误消息。你怎么看?
    • @Mario 编辑了我的答案以提供更多说明
    • 我现在明白你的意思了。我看了看视频,真的很不错,谢谢分享。是的,我认为有效载荷突变类型非常有效,我不知道定义这种类型很常见。目前,在我们的应用程序中,我们的类型只是属于我们业务逻辑一部分的对象(用户、队列、客户端、指标……)
    【解决方案2】:

    我使用带有 prisma 的 graphql 服务器,当删除某些东西时,prisma 返回有关确实被删除的东西的信息。这很好,因为当您从客户端执行删除并返回有关它的响应时,可以帮助您通过更新缓存来更改 ui

    【讨论】:

    • 是的,我认为这是一个不错的选择。就我而言,我不控制 API,因此无法进行更改。我必须处理 http 204。