就像 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.