GraphQL.JS 文档
传递参数

就像 REST API 一样,将参数传递到 GraphQL API 中的端点是很常见的。通过在结构语言中定义参数,类型检查会自动进行。每个参数都必须命名并具有类型。例如,在 基本类型文档 中,我们有一个名为 rollThreeDice 的端点:

¥Just like a REST API, it’s common to pass arguments to an endpoint in a GraphQL API. By defining the arguments in the schema language, typechecking happens automatically. Each argument must be named and have a type. For example, in the Basic Types documentation we had an endpoint called rollThreeDice:

type Query {
  rollThreeDice: [Int]
}

我们可能需要一个更通用的函数来掷 numDice 个骰子,每个骰子都有 numSides 面,而不是硬编码“三”。我们可以向 GraphQL 结构语言添加参数,如下所示:

¥Instead of hardcoding “three”, we might want a more general function that rolls numDice dice, each of which have numSides sides. We can add arguments to the GraphQL schema language like this:

type Query {
  rollDice(numDice: Int!, numSides: Int): [Int]
}

Int! 中的感叹号表示 numDice 不能为空,这意味着我们可以跳过一些验证逻辑以使我们的服务器代码更简单。我们可以让 numSides 为空并假设默认情况下骰子有 6 个面。

¥The exclamation point in Int! indicates that numDice can’t be null, which means we can skip a bit of validation logic to make our server code simpler. We can let numSides be null and assume that by default a die has 6 sides.

到目前为止,我们的解析器函数没有任何参数。当解析器接受参数时,它们作为一个“args”对象传递,作为函数的第一个参数。所以 rollDice 可以实现为:

¥So far, our resolver functions took no arguments. When a resolver takes arguments, they are passed as one “args” object, as the first argument to the function. So rollDice could be implemented as:

var root = {
  rollDice(args) {
    var output = []
    for (var i = 0; i < args.numDice; i++) {
      output.push(1 + Math.floor(Math.random() * (args.numSides || 6)))
    }
    return output
  },
}

对这些参数使用 ES6 解构赋值 很方便,因为你知道它们的格式。所以我们也可以将 rollDice 写为

¥It’s convenient to use ES6 destructuring assignment for these parameters, since you know what format they will be. So we can also write rollDice as

var root = {
  rollDice({ numDice, numSides }) {
    var output = []
    for (var i = 0; i < numDice; i++) {
      output.push(1 + Math.floor(Math.random() * (numSides || 6)))
    }
    return output
  },
}

如果你熟悉解构,这会更好一些,因为定义 rollDice 的代码行告诉你参数是什么。

¥If you’re familiar with destructuring, this is a bit nicer because the line of code where rollDice is defined tells you about what the arguments are.

托管此 rollDice API 的服务器的完整代码是:

¥The entire code for a server that hosts this rollDice API is:

var express = require("express")
var { createHandler } = require("graphql-http/lib/use/express")
var { buildSchema } = require("graphql")
 
// Construct a schema, using GraphQL schema language
var schema = buildSchema(/* GraphQL */`
  type Query {
    rollDice(numDice: Int!, numSides: Int): [Int]
  }
`)
 
// The root provides a resolver function for each API endpoint
var root = {
  rollDice({ numDice, numSides }) {
    var output = []
    for (var i = 0; i < numDice; i++) {
      output.push(1 + Math.floor(Math.random() * (numSides || 6)))
    }
    return output
  },
}
 
var app = express()
app.all(
  "/graphql",
  createHandler({
    schema: schema,
    rootValue: root,
  })
)
app.listen(4000)
console.log("Running a GraphQL API server at localhost:4000/graphql")

当你调用此 API 时,你必须按名称传递每个参数。因此,对于上面的服务器,你可以发出此 GraphQL 查询来掷三个六面骰子:

¥When you call this API, you have to pass each argument by name. So for the server above, you could issue this GraphQL query to roll three six-sided dice:

{
  rollDice(numDice: 3, numSides: 6)
}

如果你使用 node server.js 运行此代码并浏览到 http://localhost:4000/graphql,你可以尝试此 API。

¥If you run this code with node server.js and browse to http://localhost:4000/graphql you can try out this API.

当你在代码中传递参数时,通常最好避免自己构建整个查询字符串。相反,你可以使用 $ 语法在查询中定义变量,并将变量作为单独的映射传递。

¥When you’re passing arguments in code, it’s generally better to avoid constructing the whole query string yourself. Instead, you can use $ syntax to define variables in your query, and pass the variables as a separate map.

例如,上面调用我们的服务器的一些 JavaScript 代码是:

¥For example, some JavaScript code that calls our server above is:

var dice = 3
var sides = 6
var query = /* GraphQL */`query RollDice($dice: Int!, $sides: Int) {
  rollDice(numDice: $dice, numSides: $sides)
}`
 
fetch("/graphql", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Accept: "application/json",
  },
  body: JSON.stringify({
    query,
    variables: { dice, sides },
  }),
})
  .then(r => r.json())
  .then(data => console.log("data returned:", data))

在 GraphQL 中使用 $dice$sides 作为变量意味着我们不必担心客户端的转义。

¥Using $dice and $sides as variables in GraphQL means we don’t have to worry about escaping on the client side.

通过基本类型和参数传递,你可以实现可以在 REST API 中实现的任何内容。但 GraphQL 支持更强大的查询。如果你了解如何 定义你自己的对象类型,则可以将多个 API 调用替换为单个 API 调用。

¥With basic types and argument passing, you can implement anything you can implement in a REST API. But GraphQL supports even more powerful queries. You can replace multiple API calls with a single API call if you learn how to define your own object types.