对现有REST API更新为GraphQL API
背景
一个痛点吧,rest api 可以获取一个接口的全量数据[不管用的上用不上,想不想用,都一股脑的全吐给你],这样就造成一个问题
每次数据传输量都和很大,尤其遇到当一个API被多处调用时,每处需要的数据字段各有不同,当一个rest api接口为了兼容每个请求方
所需要的数据时,就会对返回的大json进行不断地冗余字段,导致各个接收方会活得一些无用的字段[也有可能有的字段涉及到法律问题]
请求方不想获取这些字段进行使用进而不进行请求,根据这一背景,要对每个rest接口逻辑进行最小量修改使其更新成GraphQL api接口
使用框架及语言
python 3.6 Flask 框架
GraphQL API需求
1、接收关键词参数进行模糊查询 [id]
2、接收关键词来控制返回数量 默认返回5个 [count]
3、控制最外层返回参数
需要新增安装的模块
pip install Flask-GraphQL graphene
基本知识
属性参数
class Query(ObjectType): hello = String( name=String( name="HELLO", # 覆盖字段的名称 description="XXXXXXXXXX", # 在GraphiQL浏览器中显示的类型的描述。 required=True, # 如果为True,则服务器将对此字段强制执行一个值。请参阅NonNull。默认值为False。 deprecation_reason="SSSSSSSSS" # 提供该字段的弃用原因。 default_value="stranger" # 提供字段的默认值。 ) )
基本标量
graphene.String:表示文本数据,以UTF-8字符序列表示。 GraphQL最常使用String类型来表示人类可读的自由格式文本。 graphene.Int:表示非小数符号整数。根据GraphQL规范,Int是带符号的32位整数 graphene.Float:表示IEEE 754指定的带符号双精度分数值 graphene.Boolean:表示是或否。 graphene.ID:表示唯一的标识符,通常用于重新获取对象或用作缓存的键。 ID类型以字符串形式显示在JSON响应中; 但是,它并不旨在人类可读。 当期望作为输入类型时,任何字符串(例如“ 4”)或整数(例如4)输入值都将被接受为ID。 graphene.types.datetime.Date:表示由iso8601指定的日期值。 graphene.types.datetime.DateTime:表示由iso8601指定的DateTime值。 graphene.types.datetime.Time:表示由iso8601指定的时间值。 graphene.types.json.JSONString:表示一个JSON字符串。
原始单条数据返回结构
描述
[{代表一条数据},{},{}]
数据结构
[ { "one": [ "xxx", "xxxxxx" ], "two": "xxxxxxxxxxx", "image": { "large_image": "xxxxxx", "medium_image": "xxxxx", "small_image": "xxx", "swatch_image": "xxxx" }, "four": "xxxxxxxxx", "id": "XXXXXSDSDSDSDSD", "six": "XXXXXXXX", "seven": { "xxx": "xxxxx", "xxxxx": "xxxxx" } } ]
解决办法
import collections from flask import Flask from flask_graphql.graphqlview import GraphQLView from graphene import ObjectType, String, Schema, Int, List, JSONString class Conversion(): """json data to GraphQL data""" def __init__(self): self.outpot = ['one', 'two', 'image', 'four', 'id', 'six', 'seven'] # 定义规范化输出字段 def cover(self, data): """ data: 原始json数据 PS: 如果想看json data 转换结构 可直接将数据代入此方法 """ Person = collections.namedtuple("Person", self.outpot) outdict = {} for dt in data: resp = collections.OrderedDict() for tp in self.outpot: resp[tp] = dt[tp] outdict[data.index(dt)] = Person(*resp.values()) return outdict class PersonType(ObjectType): one = List(String) two = String() image = JSONString() four = String() id = String() six = String() seven = JSONString() def resolve_one(person, info): return person.one def resolve_two(person, info): return person.two def resolve_image(person, info): return person.image def resolve_four(person, info): return person.four def resolve_id(person, info): return person.id def resolve_six(person, info): return person.six def resolve_seven(person, info): return person.seven class Query(ObjectType): """ GraphQL API 方法有 search 输入参数为 id count """ search = List(PersonType, id=String(), count=Int(default_value=5), description="Get search details") def resolve_search(root, info, id, count): data = 原始获取数据方式(id) response = Conversion().cover(data) resp = list(response.values())[:count] return resp schema = Schema(query=Query) app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True, pretty=True)) if __name__ == '__main__': app.run()
测试方法
1、手写requests 请求
2、postman
3、浏览器直接请求 url [http://127.0.0.1:5000/graphq]
请求结构
浏览器直接请求测试结构
{ search(id: "lslsl", count:3) { one two id image } }

浙公网安备 33010602011771号