graphql
仅仅提供了 schema 与 operation/query 的用法,当我们在 web 中使用 graphql
时,就需要使用 HTTP
把 graphql
隔离为 client
与 server
两端。想象一个流程:
- 前端发送 operation 到后端
- 后端维护一个 schema
- 后端根据前端的 operation 对照自己的 schema,查询出数据返回给前端
# Request
前端需要根据自己构造的 query 去后端请求数据,而一个 query 可以由以下几个元素构成,通过 get/post 传递数据。而目前流行的框架比如 apollo-server (opens new window),也是这样处理
- query
- operationName
- variables
在客户端无需多余的库进行支持,仅仅按照以前的方式组织 Body 发送数据即可。当然为了更好的缓存及类型提示,在前端也可以使用 apollo-client
一些库协助进行 GraphQL 查询。
// url 统一入口,但可以使用 operationName 作为 querystring 方便 debug
const url = '/graphql?HELLO'
// 如果是 POST 请求,构造以下 body 数据
const body = {
query: 'query HELLO { hello }',
operationName: 'HELLO',
variables: {}
}
// 如果是 GET 请求,构造 query string
const qs = querystring.encode(body)
// 向后端发送请求数据
const response = await fetch(url, {
body
}).then(res => res.json())
// {
// data: {
// hello: 'hello, world'
// },
// errors: null
// }
# Response: 一个简单的 GraphQL Server
对于 GraphQL 而言,前端仅仅是构造请求,而无需对 Query 进行解析,最重要的工作量放在服务端实现,如解析 GraphQL、执行 Operation 等。
我们在这里手动实现一个简单的 GraphQL Server。
import http from 'node:http'
import getRawBody from 'raw-body'
import { graphql } from 'graphql'
import { makeExecutableSchema } from '@graphql-tools/schema'
class GraphQLServer {
constructor ({ typeDefs, resolvers }) {
this.schema = makeExecutableSchema({
typeDefs,
resolvers
})
}
callback () {
return async (req, res) => {
const buffer = await getRawBody(req)
const {
query,
operationName,
variables
} = JSON.parse(buffer.toString())
const result = await graphql({
schema: this.schema,
source: query,
variableValues: variables,
operationName
})
res.end(JSON.stringify(result))
}
}
listen (...args) {
const server = http.createServer(this.callback())
server.listen(...args)
}
}
export default GraphQLServer
如此,我们在后端仅仅需要关注如何写好 Schema?
import GraphQLServer from './index.mjs'
const typeDefs = `
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`
const books = [
{
title: '三国演义',
author: '施耐庵',
},
{
title: '西游记',
author: '罗贯中',
},
]
const resolvers = {
Query: {
books: () => {
return books
}
}
}
const app = new GraphQLServer({ typeDefs, resolvers })
app.listen(4000)