UU Blog

Python的GraphQL库graphene-python的使用

开始

什么是 GraphQL?

GraghQL的介绍,概览和概念,参考 官方介绍

让我们构建一个基本的GraphQL schema.

依赖

  • Python(2.7, 3.4, 3.5, 3.6, pypy)
  • Graphene (2.0)

项目安装

1
pip install "graphene>=2.0"

创建一个基础的Schema

一个描述你数据模型的GraphQL Schema,和提供GraphQL 服务,关联对应的解析方法,该方法知道怎样获取对应的数据.

我们将创建一个非常简单的schema,一个Query,只有一个field:hello和输入名字.当我们查询它,它应当返回`”Hello {argument}”.

1
2
3
4
5
6
7
8
9
import graphene

class Query(graphene.ObjectType):
hello = graphene.String(argument=graphene.String(default_value="stranger"))

def resolve_hello(self, info, argument):
return 'Hello ' + argument

schema = graphene.Schema(query=Query)

查询

然后我们开始查询我们的schema:

1
2
3
4
5
6
result = schema.execute('{ hello }')
print(result.data['hello']) # "Hello stranger"

# or passing the argument in the query
result = schema.execute('{ hello (argument: "graph") }')
print(result.data['hello']) # "Hello graph"

类型参考 (Types Reference)

Enums 枚举型

Enum是一个特殊GraphQL类型,表示一组不重复的唯一的符号名,和它的常量值.

定义

你可以使用类创建一个Enum:

1
2
3
4
5
6
import graphene

class Episode(graphene.Enum):
NEWHOPE = 4
EMPIRE = 5
JEDI = 6

也可以直接实例化一个Enum:

1
Episode = graphene.Enum('Episode', [('NEWHOPE', 4), ('EMPIRE', 5), ('JEDI', 6)])

Value 描述

如果需要对一个enume value添加描述,添加description属性.

1
2
3
4
5
6
7
8
9
10
class Episode(graphene.Enum):
NEWHOPE = 4
EMPIRE = 5
JEDI = 6

@property
def description(self):
if self == Episode.NEWHOPE:
return 'New Hope Episode'
return 'Other episode'

Python Enums 使用

如果Enums已经存在了,可以使用Enum.from_enum 函数重用它

1
graphene.Enum.from_enum(AlreadyExistingPyEnum)

Enum.from_enum 支持descriptiondeprecation_reason lambdas 作为你添加描述之类的.你可以不用改变原型:

1
graphene.Enum.from_enum(AlreadyExistingPyEnum, description=lambda value: return 'foo' if value == AlreadyExistingPyEnum.Foo else 'bar')

说明

graphene.Enum内部使用了enum.Enum

在Python中,Enum 初始化后你访问一个成员可以这样

1
2
3
4
5
6
7
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

assert Color(1) == Color.RED

然而.在GrapheneEnum你需要调用get方法来实现同样的效果:

1
2
3
4
5
6
7
from graphene import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

assert Color.get(1) == Color.RED

Scalars类型

所有Scalar类型允许跟随参数.

可选项:

  • name: string

覆盖字段名

  • description: string

类型描述.展示在GraphQL browser

  • required: boolean

如果为True则强制要求填写该字段.默认为False

  • deprecation_reason: string

提供描述该字段反对原因

  • default_value: any

提供默认值

基础scalars

基本 Scalar类型:

  • graphene.String

文本数据, UTF-8编码.大多时候使用存储可视的字符.

  • graphene.Int

±整数,取值范围 -(2^53 - 1) and 2^53 - 1

  • graphene.Float

有小数点的,取值范围 -(2^53 - 1) and 2^53 - 1

  • graphene.Boolean

布尔值

  • graphene.ID

唯一字段,经常用来提取对象或者作为缓存的key. 在json中,返回为string类型.

输入的数字为字符串类型或者整数型都可以.

  • graphene.types.datetime.Date

Represents a Date value as specified by iso8601.

  • graphene.types.datetime.DateTime

Represents a DateTime value as specified by iso8601.

  • graphene.types.datetime.Time

Represents a Time value as specified by iso8601.

  • graphene.types.json.JSONString

JSON string.

自定义scalar

你可以创建自定义的scalar.以下例子创建一个 Datatime scaler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import datetime
from graphene.types import Scalar
from graphql.language import ast

class DateTime(Scalar):
'''DateTime Scalar Description'''

@staticmethod
def serialize(dt):
return dt.isoformat()

@staticmethod
def parse_literal(node):
if isinstance(node, ast.StringValue):
return datetime.datetime.strptime(
node.value, "%Y-%m-%dT%H:%M:%S.%f")

@staticmethod
def parse_value(value):
return datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")

Mounting Scalars

Scalars挂载objectType,Interface 或者 Mutation 作为 Field.

1
2
3
4
5
6
class Person(graphene.ObjectType):
name = graphene.String()

# 等价于:
class Person(graphene.ObjectType):
name = graphene.Field(graphene.String)

Types mounted in a Field act as Arguments.

1
2
3
4
graphene.Field(graphene.String, to=graphene.String())

# 等价于:
graphene.Field(graphene.String, to=graphene.Argument(graphene.String))

Lists and Non-Null 类型

Object类型,scalars和enums是你只能在Graphene上定义的类型.但是当你查询变量声明.或者应用这些附加类型修改或者验证这些值.

NonNull

1
2
3
4
import graphene

class Character(graphene.ObjectType):
name = graphene.NonNull(graphene.String)

这里我们使用了string类型和标记为 非空(Non-Null),用NonNull类包裹着.这意味着我们的服务器期望这个字段返回一个非空字符串.

如果最终它获取到的是null值,将触发GraphQL的异常错误.让客户端知道出错了.

以上提供NonNull代码片段等价于:

1
2
3
4
import graphene

class Character(graphene.ObjectType):
name = graphene.String(required=True)

List

1
2
3
4
import graphene

class Character(graphene.ObjectType):
appears_in = graphene.List(graphene.String)

标记一个类型为List类型,指示这个字段将返回的是列表类型的数据.

NonNull Lists

标记为非空列表

1
2
3
4
import graphene

class Character(graphene.ObjectType):
appears_in = graphene.List(graphene.NonNull(graphene.String))

上文的结果类型定义:

1
2
3
type Character {
appearsIn: [String!]
}

ObjectTypes 对象类型

一个ObjectType,限定你源数据的信息,它包含基本字段和你查询数据的行为.

  • 每个ObjectType都是Python类,继承自graphene.ObjectType
  • 每个ObjectType属性都可以作为字段

例子

这个例子模型定义了一个 Person:

1
2
3
4
5
6
7
8
9
import graphene

class Person(graphene.ObjectType):
first_name = graphene.String()
last_name = graphene.String()
full_name = graphene.String()

def resolve_full_name(self, info):
return '{} {}'.format(self.first_name, self.last_name)

上面的 Person ObjectType 对应的schema:

1
2
3
4
5
type Person {
firstName: String
lastName: String
fullName: String
}

Resolvers (解析器)

一个resolver对应ObjectType字段的解析方法.

没有意外的话,一个 ObjectType 字段(field)对应的方法是 resolve_{field_name}.

resolvers默认接收的参数是 info*args.

NOTE:

ObjectType中resolvers是被作为 staticmethod 对待的. 所以,第一个参数不必是实际的实例,比如 self 或者 root

例子

这个模型定义了一个Query 类型,有一个 reverse字段,接收了 word参数,使用 resolve_reverse 方法解析.

1
2
3
4
5
6
7
import graphene

class Query(graphene.ObjectType):
reverse = graphene.String(word=graphene.String())

def resolve_reverse(self, info, word):
return word[::-1]

参考资料

给作者打一针鸡血