Skip to content

GraphQL ​

GraphQL是一种用于API的查询语言,也是一个用于执行查询的服务器运行时。它允许客户端精确地请求他们所需的数据,并能够聚合来自多个源的数据。

18.1 GraphQL简介 ​

GraphQL由Facebook开发,用来解决传统REST API的不足。与REST API不同,GraphQL允许客户端指定请求的精确结构,从而减少不必要的数据传输,并能够在单个请求中获取所需的所有数据。

18.1.1 GraphQL的特点 ​
  • 声明式数据获取:客户端指定所需的数据结构,服务器返回相应的数据。
  • 减少网络请求:在一个请求中获取多个资源的数据。
  • 强类型系统:通过模式(Schema)定义API的类型和关系,确保数据的准确性。
  • 实时更新:支持订阅机制(Subscription),可以实现实时数据更新。
18.1.2 GraphQL与REST的对比 ​
特点GraphQLREST
数据获取客户端指定所需数据服务器定义数据结构
数据传输单个请求可以获取多个资源的数据每个请求获取一个资源的数据
强类型系统有强类型模式无强类型约束
实时更新支持订阅机制需要额外实现
版本管理无需版本管理,通过模式演进需要维护多个版本

18.2 GraphQL的基本概念 ​

18.2.1 查询(Query) ​

查询是用于获取数据的操作。客户端通过查询请求特定的数据字段,服务器根据查询返回相应的数据。

示例查询:

graphql
query {
  user(id: 1) {
    id
    name
    email
  }
}
18.2.2 变更(Mutation) ​

变更是用于修改数据的操作。客户端通过变更请求修改数据,服务器执行相应的操作并返回结果。

示例变更:

graphql
mutation {
  createUser(input: { name: "Alice", email: "alice@example.com" }) {
    id
    name
    email
  }
}
18.2.3 订阅(Subscription) ​

订阅是用于实时更新的操作。客户端通过订阅请求数据的实时更新,服务器在数据发生变化时推送更新数据。

示例订阅:

graphql
subscription {
  userCreated {
    id
    name
    email
  }
}
18.2.4 类型系统 ​

GraphQL具有强类型系统,通过模式(Schema)定义API的类型和关系。常见的类型包括标量类型、对象类型、枚举类型、输入类型等。

示例模式定义:

graphql
type User {
  id: ID!
  name: String!
  email: String!
}

type Query {
  user(id: ID!): User
}

type Mutation {
  createUser(input: CreateUserInput!): User
}

input CreateUserInput {
  name: String!
  email: String!
}

18.3 在Go中使用GraphQL ​

18.3.1 安装GraphQL库 ​

在Go中使用GraphQL,需要安装相关的库。常用的GraphQL库有graphql-go和gqlgen。

使用gqlgen库:

bash
go get github.com/99designs/gqlgen
18.3.2 定义GraphQL模式 ​

定义GraphQL模式文件(schema.graphql):

graphql
type User {
  id: ID!
  name: String!
  email: String!
}

type Query {
  user(id: ID!): User
}

type Mutation {
  createUser(input: CreateUserInput!): User
}

input CreateUserInput {
  name: String!
  email: String!
}
18.3.3 生成Go代码 ​

使用gqlgen生成相应的Go代码:

bash
go run github.com/99designs/gqlgen init
18.3.4 实现Resolver ​

gqlgen 会在 graph/resolver.go 中生成 Resolver 骨架,在其中补充业务逻辑:

go
type Resolver struct{}

func (r *Resolver) Query() QueryResolver {
    return &queryResolver{r}
}

func (r *Resolver) Mutation() MutationResolver {
    return &mutationResolver{r}
}

type queryResolver struct{ *Resolver }

func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
    // 根据ID获取用户数据
    return &model.User{ID: id, Name: "Alice"}, nil
}

type mutationResolver struct{ *Resolver }

func (r *mutationResolver) CreateUser(ctx context.Context, input model.CreateUserInput) (*model.User, error) {
    // 创建用户数据
    return &model.User{ID: "1", Name: input.Name, Email: input.Email}, nil
}
18.3.5 启动GraphQL服务器 ​

在main.go中启动GraphQL服务器(新版 gqlgen 的 handler 位于 graphql/handler,Playground 位于 graphql/playground,生成的代码在 graph 包内):

go
package main

import (
    "log"
    "net/http"

    "github.com/99designs/gqlgen/graphql/handler"
    "github.com/99designs/gqlgen/graphql/playground"
    "github.com/myapp/graph"
)

func main() {
    srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))

    http.Handle("/", playground.Handler("GraphQL playground", "/query"))
    http.Handle("/query", srv)

    log.Println("Server is running on http://localhost:8080/")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

18.4 GraphQL的高级功能 ​

18.4.1 批量请求(Batching) ​

GraphQL支持批量请求,通过DataLoader等技术减少多次网络请求,提高性能。

18.4.2 分页(Pagination) ​

GraphQL提供了多种分页实现方式,如基于偏移量的分页和基于游标的分页,方便客户端获取大数据集。

示例分页查询:

graphql
query {
  users(first: 10, after: "cursor") {
    edges {
      node {
        id
        name
      }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
18.4.3 指令(Directives) ​

GraphQL指令用于在查询或模式中添加元数据或执行特定操作。常见的指令包括@include和@skip。

示例指令(@include 依赖变量,需要在查询中先声明变量):

graphql
query ($includeEmail: Boolean!) {
  user(id: 1) {
    id
    name
    email @include(if: $includeEmail)
  }
}
18.4.4 自定义标量类型 ​

GraphQL允许定义自定义标量类型,如日期、时间等,用来覆盖内置标量不支持的类型。

示例自定义标量类型:

graphql
scalar DateTime

type User {
  id: ID!
  name: String!
  createdAt: DateTime!
}

GraphQL 的核心是查询、变更、订阅三种操作加一套类型系统;Go 这边用 gqlgen 从 schema 生成代码,在 Resolver 里补业务逻辑即可。

参考资料 ​

同层页面 ​

相关页面 ​

Hello Golang