GraphQL是一种用于API的查询语言。
它提供了一种标准的方法:
描述服务器在静态类型架构中提供的数据
在查询中请求数据,该查询准确地描述了数据需求和在只包含请求的数据的响应中接收数据。
Graphene是一个库,在Python中实现GraphQLAPI的工具。
Graphene与最流行的web框架和ORM集成在一起,功能齐全。Graphene生成完全符合GraphQL规范的模式,并提供用于构建中继兼容API的工具和模式
安装Graphene:
pip3 install graphene
先来一个简单的例子
from graphene import ObjectType, String, Schema
class Query(ObjectType):
# 定义了一个字段“hello”,其中只有一个参数“first_name”
# 默认情况下,参数名称将自动以驼峰形式转换架构中的first_name为firstName
hello = String(first_name=String(default_value="stranger"))
goodbye = String()
# resolver方法获取字段的GraphQL上下文(root,info)和 argument(first_name),并返回查询response的数据
def resolve_hello(root, info, first_name):
return f'Hello {first_name}!'
def resolve_goodbye(root, info):
return 'See you'
schema = Schema(query=Query)
Schema Definition Language (SDL)为:
GraphQL模式定义语言中,可以描述示例代码定义的字段
type Query {
hello(firstName: String = "stranger"): String
goodbye: String
}
查询
然后,可以通过传递GraphQL查询字符串来执行,从而开始查询Schema:
# 查询字段(使用默认参数)
query_string = '{ hello }'
result = schema.execute(query_string)
print(result.data['hello'])
# "Hello stranger!"
# 或在查询中传递参数
query_with_argument = '{ hello(firstName: "luwei") }'
result = schema.execute(query_with_argument)
print(result.data['hello'])
# "Hello luwei!"
Schema
GraphQL模式定义了API中字段之间的类型和关系。
Schema是通过提供每个操作、query(强制)、mutation和subscription的根ObjectType来创建的
Schema将收集与root操作相关的所有类型定义,然后将它们提供给validator和executor
my_schema = Schema(
query=RootQuery,
mutation=RootMutation,
subscription=RootSubscription
)
RootQuery只是一种特殊的ObjectType,它定义了作为API入口点的字段。RootMutation和RootSubscription类似于RootQuery,但用于不同的操作类型:
query:查询获取数据
mutation:更改数据并检索更改
subscription:将更改实时发送到客户端
Querying
若要查询架构,请对其调用execute方法
query_string = 'query whoIsMyFriend { myBestFriend { lastName } }' # whoIsMyBestFriend 可以不填
my_schema.execute(query_string)
Types
在某些情况下,Schema无法访问计划拥有的所有类型。例如,当一个字段返回一个Interface时,Schema不知道如何实现
在这种情况下,我们需要在创建Schema时使用types参数:
my_schema = Schema(
query=RootQuery,
types=[SomeExtraObjectType, ]
)
Auto camelCase field names
默认情况下,所有字段和参数名称都将从snake_case转换为camelCase(因为API通常由js/mobile客户端使用)
例如,对于ObjectType,last_name字段名将转换为lastName:
class Person(graphene.ObjectType):
last_name = graphene.String()
first_name = graphene.String(name='_first_Name')
如果不想转换,可以为字段构造函数提供一个名称参数。first_name转换为_first_Name(无需进一步转换)
查询应该如下:
{
lastName
_first_Name
}
要禁用转换,在Schema实例化时将auto_camelcase设置为False:
my_schema = Schema(
query=RootQuery,
auto_camelcase=False,
)
Scalars
Scalar类型表示查询叶子处的具体值。Graphene提供了几种开箱即用的内置类型,它们表示Python中的常见值。也可以创建自己的Scalar类型,以更好地表达数据模型中可能存在的值。
所有Scalar类型都接受以下参数。所有选项都是可选的 (除了以下这几个,传递的都为值参数):
name
: string:覆盖字段的名称
description
: string:显示的类型的描述
required
: boolean: 如果为True,则将强制执行此字段的值,默认值为False
deprecation_reason
: string: 描述字段的弃用理由
default_value
: any: 为字段提供的默认值
内置的scalars
graphene.String
: 表示文本数据,表示为UTF-8字符序列
graphene.Int
: 整型
graphene.Float
: 浮点型
graphene.Boolean
:Bool型
graphene.ID
:表示一个唯一的标识符,通常用于重写对象或作为缓存的键
graphene.Date
: 日期值 例子如下:
import datetime
from graphene import Schema, ObjectType, Date
class Query(ObjectType):
one_week_from = Date(required=True, date_input=Date(required=True)) # date_input为查询输入的参数
def resolve_one_week_from(root, info, date_input):
assert date_input == datetime.date(2023, 4, 3)
return date_input + datetime.timedelta(weeks=1)
schema = Schema(query=Query)
results = schema.execute("""
query {
oneWeekFrom(dateInput: "2023-04-03")
}
""")
assert results.data == {"oneWeekFrom": "2023-04-03"}
graphene.DateTime
:DateTime值 例子如下:
import datetime
from graphene import Schema, ObjectType, DateTime
class Query(ObjectType):
one_hour_from = DateTime(required=True, datetime_input=DateTime(required=True))
def resolve_one_hour_from(root, info, datetime_input):
assert datetime_input == datetime.datetime(2023, 4, 3, 15, 15, 5)
return datetime_input + datetime.timedelta(hours=1)
schema = Schema(query=Query)
results = schema.execute("""
query {
oneHourFrom(datetimeInput: "2023-04-03T15:15:05")
}
""")
assert results.data == {"oneHourFrom": "2023-04-03T15:15:05"}
graphene.Time
: Time 值 例子如下:
import datetime
from graphene import Schema, ObjectType, Time
class Query(ObjectType):
one_hour_from = Time(required=True, time_input=Time(required=True))
def resolve_one_hour_from(root, info, time_input):
assert time_input == datetime.time(15, 4, 5)
tmp_time_input = datetime.datetime.combine(datetime.date(1, 1, 1), time_input)
return (tmp_time_input + datetime.timedelta(hours=1)).time()
schema = Schema(query=Query)
results = schema.execute("""
query {
oneHourFrom(timeInput: "15:15:05")
}
""")
assert results.data == {"oneHourFrom": "16:15:05"}
graphene.Decimal
:Decimal值 例子如下:
import decimal
from graphene import Schema, ObjectType, Decimal
class Query(ObjectType):
add_one_to = Decimal(required=True, decimal_input=Decimal(required=True))
def resolve_add_one_to(root, info, decimal_input):
assert decimal_input == decimal.Decimal("10.50")
return decimal_input + decimal.Decimal("1")
schema = Schema(query=Query)
results = schema.execute("""
query {
addOneTo(decimalInput: "15.50")
}
""")
assert results.data == {"addOneTo": "16.50"}
graphene.JSONString
:JSON 类型 例子如下:
from graphene import Schema, ObjectType, JSONString, String
class Query(ObjectType):
update_json_key = JSONString(
required=True,
json_input=JSONString(required=True),
key=String(required=True),
value=String(required=True)
)
def resolve_update_json_key(root, info, json_input, key, value):
assert json_input == {"name": "lu wei"}
json_input[key] = value
return json_input
schema = Schema(query=Query)
results = schema.execute("""
query {
updateJsonKey(jsonInput: "{\\"name\\": \\"luwei\\"}", key: "height", value: "180")
}
""")
assert results.data == {'updateJsonKey': '{"name": "lu wei", "height": "180"}'}
graphene.Base64
: Base64 类型 例子如下:
from graphene import Schema, ObjectType, Base64
class Query(ObjectType):
increment_encoded_id = Base64(
required=True,
base64_input=Base64(required=True),
)
def resolve_increment_encoded_id(root, info, base64_input):
assert base64_input == "4"
return int(base64_input) + 1
schema = Schema(query=Query)
results = schema.execute("""
query {
incrementEncodedId(base64Input: "NA==")
}
""")
assert results.data == {"incrementEncodedId": "NQ=="}
自定义scalars
也可以为Schema创建自定义scalars。以下是创建DateTime scalars的示例:
import datetime
from graphene.types import Scalar
from graphql.language import ast
class DateTime(Scalar):
'''自定义DateTime Scalar'''
@staticmethod
def serialize(dt):
return dt.isoformat()
@staticmethod
def parse_instance(node, _variables=None):
'''判断类型是否相等 并解析值'''
if isinstance(node, ast.StringValueNode):
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")
安装 Scalars
安装scalars在ObjectType、Interface或Mutation中充当字段
class Person(graphene.ObjectType):
name = graphene.String()
# 等价与:
class Person(graphene.ObjectType):
name = graphene.Field(graphene.String)
注意:当直接使用Field构造函数时,传递类型而不是实例
将scalars当作Field中的参数类型
graphene.Field(graphene.String, my_name=graphene.String()) # my_name 为值参数
# 等价于
graphene.Field(graphene.String, my_name=graphene.Argument(graphene.String))