GraphQL.JS 文档
对象类型

在许多情况下,你不希望从 API 返回数字或字符串。你想要返回一个具有其自身复杂行为的对象。GraphQL 非常适合于此。

¥In many cases, you don’t want to return a number or a string from an API. You want to return an object that has its own complex behavior. GraphQL is a perfect fit for this.

在 GraphQL 结构语言中,定义新对象类型的方式与我们在示例中定义 Query 类型的方式相同。每个对象都可以具有返回特定类型的字段和接受参数的方法。例如,在 传递参数 文档中,我们有一个随机掷骰子的方法:

¥In GraphQL schema language, the way you define a new object type is the same way we have been defining the Query type in our examples. Each object can have fields that return a particular type, and methods that take arguments. For example, in the Passing Arguments documentation, we had a method to roll some random dice:

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

如果我们希望随着时间的推移有越来越多的基于随机骰子的方法,我们可以使用 RandomDie 对象类型来实现。

¥If we wanted to have more and more methods based on a random die over time, we could implement this with a RandomDie object type instead.

type RandomDie {
  roll(numRolls: Int!): [Int]
}
 
type Query {
  getDie(numSides: Int): RandomDie
}

我们可以使用 ES6 类,而不是 RandomDie 类型的根级解析器,其中解析器是实例方法。此代码显示了如何实现上述 RandomDie 结构:

¥Instead of a root-level resolver for the RandomDie type, we can instead use an ES6 class, where the resolvers are instance methods. This code shows how the RandomDie schema above can be implemented:

class RandomDie {
  constructor(numSides) {
    this.numSides = numSides
  }
 
  rollOnce() {
    return 1 + Math.floor(Math.random() * this.numSides)
  }
 
  roll({ numRolls }) {
    var output = []
    for (var i = 0; i < numRolls; i++) {
      output.push(this.rollOnce())
    }
    return output
  }
}
 
var root = {
  getDie({ numSides }) {
    return new RandomDie(numSides || 6)
  },
}

对于不使用任何参数的字段,你可以使用对象的属性或实例方法。因此,对于上面的示例代码,numSidesrollOnce 实际上都可以用来实现 GraphQL 字段,因此代码也实现了以下结构:

¥For fields that don’t use any arguments, you can use either properties on the object or instance methods. So for the example code above, both numSides and rollOnce can actually be used to implement GraphQL fields, so that code also implements the schema of:

type RandomDie {
  numSides: Int!
  rollOnce: Int!
  roll(numRolls: Int!): [Int]
}
 
type Query {
  getDie(numSides: Int): RandomDie
}

将所有这些放在一起,下面是一些使用此 GraphQL API 运行服务器的示例代码:

¥Putting this all together, here is some sample code that runs a server with this GraphQL API:

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 RandomDie {
    numSides: Int!
    rollOnce: Int!
    roll(numRolls: Int!): [Int]
  }
 
  type Query {
    getDie(numSides: Int): RandomDie
  }
`)
 
// This class implements the RandomDie GraphQL type
class RandomDie {
  constructor(numSides) {
    this.numSides = numSides
  }
 
  rollOnce() {
    return 1 + Math.floor(Math.random() * this.numSides)
  }
 
  roll({ numRolls }) {
    var output = []
    for (var i = 0; i < numRolls; i++) {
      output.push(this.rollOnce())
    }
    return output
  }
}
 
// The root provides the top-level API endpoints
var root = {
  getDie({ numSides }) {
    return new RandomDie(numSides || 6)
  },
}
 
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 查询时,你可以通过嵌套 GraphQL 字段名称一次调用对象上的多个方法。例如,如果你想调用 rollOnce 掷一次骰子,并调用 roll 掷三次骰子,则可以使用以下查询来完成:

¥When you issue a GraphQL query against an API that returns object types, you can call multiple methods on the object at once by nesting the GraphQL field names. For example, if you wanted to call both rollOnce to roll a die once, and roll to roll a die three times, you could do it with this query:

{
  getDie(numSides: 6) {
    rollOnce
    roll(numRolls: 3)
  }
}

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

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

这种定义对象类型的方法通常比传统的 REST API 具有优势。你可以在一个 API 请求中获取所有这些信息,而不是执行一个 API 请求来获取有关某个对象的基本信息,然后执行多个后续 API 请求来查找有关该对象的更多信息。这可以节省带宽,使你的应用运行得更快,并简化你的客户端逻辑。

¥This way of defining object types often provides advantages over a traditional REST API. Instead of doing one API request to get basic information about an object, and then multiple subsequent API requests to find out more information about that object, you can get all of that information in one API request. That saves bandwidth, makes your app run faster, and simplifies your client-side logic.

到目前为止,我们看到的每个 API 都是为返回数据而设计的。为了修改存储的数据或处理复杂的输入,它有助于 了解变更和输入类型

¥So far, every API we’ve looked at is designed for returning data. In order to modify stored data or handle complex input, it helps to learn about mutations and input types.