GraphQL 是一种用于构建 API 的查询语言,它使用了一种类似于 JSON 的格式来描述数据,并提供了一种强大而灵活的方式来获取所需的数据。相较于传统的 REST API,GraphQL 相对简便、易用,并且具备更强的可扩展性和数据抽象能力。
本文将介绍 GraphQL 的原理和实现,帮助读者更好地理解和应用该技术。
GraphQL 工作原理
GraphQL 将请求和响应的数据模型统一成了一个名为“图”(graph)的数据结构,在该结构中,每个数据类型定义了它们之间的关系和属性。在 GraphQL 的查询中,请求的数据结构可以跨越多个资源,并合并成一个可渲染的结果。
Schema 定义
在 GraphQL 中,Schema 用于描述数据结构和数据类型的定义。它包含了类型、属性和查询的定义。每个 Schema 都包含了 Query、Mutation 和 Subscription 三个 Type,分别代表查询、变更和订阅。
因此,通过 Schema,GraphQL 知道每个字段的名字、数据类型和返回结果。Schema 也可以帮助定义被支持的查询类型和变更,而且支持自定义 Scalar 类型。
下面是一个简单的 Schema 定义:
// www.javascriptcn.com code example
type User {
id: ID!
name: String
email: String
}
type Query {
users: [User]
getUser(id: ID!): User
}该 Schema 定义了两个 Type: User 和 Query。 User Type 定义了三个字段,包括 id、name 和 email。 Query Type 定义了两个查询,分别是获取所有用户信息和根据指定 ID 获取用户信息。
查询
GraphQL 查询用于获取数据。它类似于函数调用,但是只传递查询类型作为参数,而不是直接进行函数调用。查询参数也可包含变量,这些变量提供了一种动态的输入机制,在查询过程中可以将参数引入到查询变量中。
下面是一个简单的查询示例:
query getUserName {
users {
name
}
}该查询用于获取所有用户的名字,并通过请求返回数据。
变更
GraphQL 变更用于修改数据。它通常被用于执行插入、更新和删除的操作。变更操作遵循标准的 Mutation Type 定义,Mutation Type 包含了所有可定义的变更操作。
下面是一个简单的添加用户信息的变更操作:
mutation addUser {
addUser(name: "Alice", email: "alice@gmail.com") {
id
name
email
}
}该变更操作用于添加一个新的用户信息,并通过请求返回添加的用户信息。
订阅
GraphQL 订阅用于实现实时应用程序,支持接收实时数据更新。订阅操作定义了一组事件,当这些事件发生时,将会触发 GraphQL 服务的启动并返回所请求的数据。
下面是一个简单的订阅示例:
subscription getUserNotifications {
newNotifications(userId: "1") {
message
date
}
}该订阅用于获取用户的最新通知,当用户有新消息到达时,将会返回相应的信息。
GraphQL 实现
在实现 GraphQL 时,有多种工具和库可以作为支持,例如 Apollo Server、Express、GraphQL Yoga 等。下面基于 Express 框架介绍如何实现 GraphQL 服务。
安装
首先需要安装 Express 和 GraphQL 的各种依赖库:
npm install express graphql express-graphql
创建服务器
创建一个 Express 服务实例,并在其上面创建 GraphQL API:
// www.javascriptcn.com code example
const express = require('express')
const { graphqlHTTP } = require('express-graphql')
const { buildSchema } = require('graphql')
const app = express()
const schema = buildSchema(`
type Query {
users: [User]
getUser(id: ID!): User
}
type User {
id: ID!
name: String
email: String
}
`)
const users = [
{ id: 1, name: 'Alice', email: 'alice@gmail.com' },
{ id: 2, name: 'Bob', email: 'bob@gmail.com' },
]
const root = {
users: () => users,
getUser: ({id}) => users.find(user => user.id === parseInt(id)),
}
app.use('/graphql', graphqlHTTP({
schema,
rootValue: root,
graphiql: true,
}))
app.listen(3000)上述代码中,首先定义了 GraphQL 的 Schema 和 Resolver,然后使用 express-graphql 中间件来在 Express 服务上设置 GraphQL 路由,即将 /graphql 路由请求交由 express-graphql 中间件进行处理。
启动服务后,可以通过访问 http://localhost:3000/graphql,进入 GraphiQL 页面,并且可以测试 API 调用。
测试查询
在 GraphiQL 页面进行如下查询操作:
query getUser {
getUser(id: 1) {
id
name
email
}
}点击运行按钮,即可得到返回的用户信息。
测试变更
在 GraphiQL 页面进行如下变更操作:
mutation {
addUser(name: "Lucy", email: "lucy@gmail.com") {
id
name
email
}
}点击运行按钮,即可得到返回的添加的用户信息。
测试订阅
GraphQL 订阅需要使用 WebSockets 协议,所以需要使用 apollo-server-express 等第三方库来实现订阅功能,下面是一个简单的订阅示例:
// www.javascriptcn.com code example
const { ApolloServer, gql } = require('apollo-server-express')
const { SubscriptionServer } = require('subscriptions-transport-ws')
const express = require('express')
const http = require('http')
const { execute, subscribe } = require('graphql')
const typeDefs = gql`
type Notification {
message: String!
date: String!
}
type Subscription {
newNotifications(userId: ID!): Notification
}
`
const notifications = [
{ userId: 1, message: 'Hello world', date: new Date().toString() }
]
const resolvers = {
Subscription: {
newNotifications: {
subscribe: (_, { userId }, { pubsub }) => {
const channel = `NOTIFICATIONS_${userId}`
return pubsub.asyncIterator(channel)
}
}
}
}
const app = express()
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }) => ({
req,
res,
pubsub,
})
})
const httpServer = http.createServer(app)
server.applyMiddleware({ app })
httpServer.listen(3000, () => {
console.log(`🚀 Server ready at http://localhost:3000${server.graphqlPath}`)
new SubscriptionServer({
execute,
subscribe,
schema: server.schema,
}, {
server: httpServer,
path: server.graphqlPath,
})
})
const pubsub = new PubSub()
notifications.forEach(notify => {
setInterval(() => {
pubsub.publish(`NOTIFICATIONS_${notify.userId}`, { newNotifications: notify })
}, 1000)
})上述代码中,首先定义了 Schema 和订阅 Resolver。随后使用 apollo-server-express 库来实现 GraphQL API,并使用 subscriptions-transport-ws 库来将 Subscription Server 添加到 HTTP Server。
在测试订阅时,可以使用 ApolloClient 类库进行 WebSocket 的订阅调用:
// www.javascriptcn.com code example
import { ApolloClient, InMemoryCache, gql } from '@apollo/client'
import { WebSocketLink } from '@apollo/client/link/ws'
const wsLink = new WebSocketLink({
uri: `ws://localhost:3000/graphql`,
options: {
reconnect: true,
},
})
const client = new ApolloClient({
link: wsLink,
cache: new InMemoryCache(),
})
const query = gql`
subscription {
newNotifications(userId: 1) {
message
date
}
}
`
client
.subscribe({ query })
.subscribe({
next(data) {
console.log(data)
}
})
上述代码中,首先创建了 WebSocketLink,连接到 GraphQL 服务的 ws://localhost:3000/graphql 路径,然后通过 ApolloClient 订阅 query。
结语
本文介绍了 GraphQL 的原理和实现方法,希望读者在阅读后对 GraphQL 有更深入的了解,并且可以使用 GraphQL 来构建自己的 API 应用程序。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d7be2aa941bf7134de0630