开发目标: 实现一个 Web 服务,这个服务使用 Flask 框架,API 使用 Graphql。

这个 Web 服务很简单,它提供书籍的查询与添加功能(修改和删除与添加类似,故不赘述)。通过这个例子,希望可以帮助大家了解以下两点

  1. 如何使用 Graphql 进行API设计
  2. 如何进行 Graphql 的后端开发

Install

首先,安装一下下面这几个模块。


# python 3.6 以上

pip install graphene

pip install Flask-GraphQL

API Design

下面,开始设计 API,也就是先写一份我们的 Graphql Schema(Schema Define Language,SDL)。

创建文件 books.graphql (如果 IDE 是 vscode ,可装 graphql 插件)


type Book {
    id: ID!
    name: String!
}

type Query {
    books: [Book!]!
}

type Mutation {
  add(name: String!): Book!
}

我们定义了三个东西:

  1. Book,书,相当于一个类,可以理解为资源
  2. Query,查询接口定义,我们只定义了一个查询接口
  3. Mutation,数据修改接口定义,我们定义了一个接口,增

每个GraphQL schema都有三种特殊的根类型,称为查询(Query),修改(Mutation)和订阅(Subscription)。这些根类型的字段定义了API接受的操作。我们使用了 查询和修改。

Web Service

下面,我们创建服务,创建文件 server.py,根据文档编写下面的代码(请注意,代码不是根据 API 文档自动生成的):


from flask import Flask
from flask_graphql import GraphQLView
import graphene

app = Flask(__name__)

books = []

class Book(graphene.ObjectType):
    """ Book
    """

    id = graphene.ID(description="book ID")

    name = graphene.String(description="book name")

create = lambda id, name: Book(id=id, name=name)

books.append(create(1, "The First Book"))

class Query(graphene.ObjectType):
    """ query your books
    """

    books = graphene.List(Book, description="list books")

    version = graphene.String(description="version")

    def resolve_books(self, info):
        return books

    def resolve_version(self, info):
        return "v0.1"

# Mutation

class AddBook(graphene.Mutation):
    """ Add books
    """
    Output = Book

    class Arguments:
        name = graphene.String()

    def mutate(self, info, name):
        book = create(len(books) + 1, name)
        books.append(book)
        return book

class Mutation(graphene.ObjectType):
    """ mutate books
    """
    add = AddBook.Field()

schema = graphene.Schema(query=Query, mutation=Mutation)

app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql',
    schema=schema, graphiql=True))

app.run(port=4901, debug=True)


代码分析:

  1. books 是一个全局变量,用于保存所有的 books,可把它当做数据库,很多示例都有数据库,为了保持简单,最方便运行,所以,我只用了这么一个变量
  2. Query是比较简单的,语义很清晰,和 API 文档不同的是,在 Query 中增加了一个 version,这是为了简单对比一个 restful ,如果是 restful 的话,我们要获取 booksversion 这两个资源,需要两个 API,但 graphql 只需要一个
  3. Mutation 分为两步,第一步定义一个Mutate,里面必须要有mutate方法,第二个创建Mutation,用于组合所有的Mutate
  4. /graphql 是给我们提供一个可视化的 API 展示,类似 Swagger,当然,生产环境就不要加这个了,加在开发、测试环境即可

运行代码:


python server.py

访问: http://127.0.0.1:4901/graphql ,可看到类似 Github V4 API 的 Explorer 界面。

点击最右侧的 Docs,可看到我们的 API 设计。

Query All Books

在最左侧的框中输入:


query {
  books {
    name
    id
  }
  version
}


然后,点击那个类似 “播放”(运行) 的按钮,即可在中间的框中,看到输出。

Add a Book

下面,输入:


mutation {
  add(name: "The second Book") {
    id
  }
}

运行一下,即可添加 Book。可以再运行一下上面的 query,看一下当前所有书籍。

上面是 Web 界面,我们也可以使用 curl 做测试:


curl http://127.0.0.1:4901/graphql\?query\=query%20%7Bbooks%20%7Bid%20name%20%7D%20version%7D

建议大家可以自己实现一下 removeBookupdateBook 之类的方法,加深理解。

Reference

  1. Graphql Spec
  2. Github V4
  3. Grapql Code Generate
  4. Awesome Graphql