GraphQL试用
GraphQL介绍(一种API查询语言和运行时总和,提供更高效、强大且灵活的API开发和使用方式)REST对比(Schema定义语言SDL语言)按需获取、单一端点、强类型系统、层次性查询、演进式API
测试代码:
import json
import graphene
from graphene import relay, ObjectType, Schema
from sqlalchemy import create_engine, event, Column, Integer, String, ForeignKey
from sqlalchemy.orm import scoped_session, sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from graphene_sqlalchemy import SQLAlchemyObjectType,SQLAlchemyConnectionField
from urllib.parse import quote
from flask import Flask
from flask_graphql import GraphQLView
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/test')
#connection = engine.connect()
#connection.autocommit = False
db_session = scoped_session(sessionmaker(autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def jsonStandFormat(jsondata):
return json.dumps(jsondata, sort_keys=True, indent=4, separators=(',', ':'), ensure_ascii=False)
class Laoshi(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
age = graphene.ID()
class Xuesheng(graphene.ObjectType):
id = graphene.ID()
name = graphene.String()
age = graphene.ID()
'''
测试数据
'''
global_laoshis_data = [
Laoshi(id=1, name="老师1", age=31),
Laoshi(id=2, name="老师2", age=32),
Laoshi(id=3, name="老师3", age=33),
Laoshi(id=4, name="老师4", age=34),
Laoshi(id=5, name="老师5", age=35),
Laoshi(id=6, name="老师6", age=36),
]
global_xueshengs_data = [
Xuesheng(id=1, name="学生1", age=11),
Xuesheng(id=2, name="学生2", age=12),
Xuesheng(id=3, name="学生3", age=13),
Xuesheng(id=4, name="学生4", age=14),
Xuesheng(id=5, name="学生5", age=15),
Xuesheng(id=6, name="学生6", age=16),
]
class Laoshidb(Base):
__tablename__ = 'laoshi'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
age = Column(Integer)
class Xueshengdb(Base):
__tablename__ = 'xuesheng'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
age = Column(Integer)
class LaoshiObjectType(SQLAlchemyObjectType):
class Meta:
model = Laoshidb
interfaces = (graphene.relay.Node, )
class XueshengObjectType(SQLAlchemyObjectType):
class Meta:
model = Xueshengdb
interfaces = (graphene.relay.Node, )
class Query(graphene.ObjectType):
#对于方法的定义
getLaoshiWithId = graphene.Field(Laoshi, id=graphene.ID())
getXueshengWithName = graphene.Field(Xuesheng, name=graphene.String())
getXueshengWithAge = graphene.Field(Xuesheng, age=graphene.ID())
getXueshengWithAges = graphene.List(Xuesheng, ageStr=graphene.String())
node = graphene.relay.Node.Field()
getXueshengsFromDb = SQLAlchemyConnectionField(XueshengObjectType.connection, sort=None)
laoshis = graphene.List(LaoshiObjectType, searchStr=graphene.String())
#对于方法的实现
def resolve_getLaoshiWithId(self, info, id):
#这里可以直接改为查数据库
for laos in global_laoshis_data:
if laos.id == int(id):
return laos
return None
def resolve_getXueshengWithName(self, info, name):
for xues in global_xueshengs_data:
if xues.name == name:
return xues
return None
def resolve_getXueshengWithAge(self, info, age):
for xues in global_xueshengs_data:
if xues.age == int(age):
return xues
return None
def resolve_getXueshengWithAges(self, info, ageStr):
ages = [int(i) for i in ageStr.split(',')]
res = []
for xues in global_xueshengs_data:
if xues.age in ages:
res.append(xues)
return res
#对于方法的实现
def resolve_laoshis(self, info, searchStr):
query = LaoshiObjectType.get_query(info) # SQLAlchemy query
if searchStr:
query = query.filter(Laoshidb.name.like('%'+searchStr+'%'))
return query.all()
if __name__ == '__main__':
schema = graphene.Schema(query=Query)
'''
app = Flask(__name__)
app.add_url_rule("/grapql", view_func=GraphQLView.as_view('grapql', schema=schema, graphiql=True))
app.run(debug=True)
'''
query = '''
{
getLaoshiWithId(id: 1) {
id, name, age
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
{
getXueshengWithName(name: "学生1") {
id, name, age
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
{
getXueshengWithAge(age: 12) {
id,name
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
{
getXueshengWithAges(ageStr: "14,15") {
id, name, age
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
{
getXueshengsFromDb {
edges {
node {
id, name, age
}
}
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
query {
laoshis(searchStr: "") {
id, name, age
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
query = '''
query {
laoshis(searchStr: "2") {
id, name, age
}
}
'''
result = schema.execute(query)
print(jsonStandFormat(result.data))
测试输出:
{
"getLaoshiWithId":{
"age":"31",
"id":"1",
"name":"老师1"
}
}
{
"getXueshengWithName":{
"age":"11",
"id":"1",
"name":"学生1"
}
}
{
"getXueshengWithAge":{
"id":"2",
"name":"学生2"
}
}
{
"getXueshengWithAges":[
{
"age":"14",
"id":"4",
"name":"学生4"
},
{
"age":"15",
"id":"5",
"name":"学生5"
}
]
}
{
"getXueshengsFromDb":{
"edges":[
{
"node":{
"age":14,
"id":"WHVlc2hlbmdPYmplY3RUeXBlOjE=",
"name":"学生1"
}
},
{
"node":{
"age":15,
"id":"WHVlc2hlbmdPYmplY3RUeXBlOjI=",
"name":"学生2"
}
},
{
"node":{
"age":16,
"id":"WHVlc2hlbmdPYmplY3RUeXBlOjM=",
"name":"学生3"
}
}
]
}
}
{
"laoshis":[
{
"age":30,
"id":"TGFvc2hpT2JqZWN0VHlwZTox",
"name":"老师1"
},
{
"age":31,
"id":"TGFvc2hpT2JqZWN0VHlwZToy",
"name":"老师2"
},
{
"age":32,
"id":"TGFvc2hpT2JqZWN0VHlwZToz",
"name":"老师3"
}
]
}
{
"laoshis":[
{
"age":31,
"id":"TGFvc2hpT2JqZWN0VHlwZToy",
"name":"老师2"
}
]
}
随后我弄了一个服务端:test_with_sqlalchemy_server.py
import json
import graphene
from graphene import relay, ObjectType, Schema
from sqlalchemy import create_engine, event, Column, Integer, String, ForeignKey
from sqlalchemy.orm import scoped_session, sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
from graphene_sqlalchemy import SQLAlchemyObjectType,SQLAlchemyConnectionField
from urllib.parse import quote
from flask import Flask, render_template, request
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/test')
#connection = engine.connect()
#connection.autocommit = False
db_session = scoped_session(sessionmaker(autoflush=False, bind=engine))
Base = declarative_base()
Base.query = db_session.query_property()
def jsonStandFormat(jsondata):
return json.dumps(jsondata, sort_keys=True, indent=4, separators=(',', ':'), ensure_ascii=False)
class LaoshiModel(Base):
__tablename__ = 'laoshi'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50))
age = Column(Integer)
class LaoshiObjectType(SQLAlchemyObjectType):
class Meta:
model = LaoshiModel
interfaces = (graphene.relay.Node, )
class Query(graphene.ObjectType):
laoshis = graphene.List(LaoshiObjectType, searchStr=graphene.String())
#对于方法的实现
def resolve_laoshis(self, info, searchStr):
query = LaoshiObjectType.get_query(info) # SQLAlchemy query
if searchStr:
query = query.filter(LaoshiModel.name.like('%'+searchStr+'%'))
return query.all()
schema = graphene.Schema(query=Query)
app = Flask(__name__)
@app.route("/", methods=['POST'])
def index():
query = request.form.get('query')
result = schema.execute(query)
return jsonStandFormat(result.data)
if __name__ == '__main__':
app.run(debug=True)
客户端:test_with_sqlalchemy_client.py
#coding=utf-8
import requests
import random
import os, sys
from faker import Faker
import hashlib
import json
import time
import base64
import copy
faker = Faker(locale='zh_CN')
baseurl = 'http://127.0.0.1:5000'
token = ''
#将内容转为base64格式内容
def convertToBase64(info):
try:
tmpBase64=base64.b64encode(info)
return tmpBase64
except Exception as e:
print('异常:',e)
#将base64格式内容转为正常信息
def convertTostring(base64Info):
try:
tmpBytes=base64.b64decode(base64Info)
tmpStr=tmpBytes.decode()
return tmpStr
except Exception as e:
print('异常:',e)
def md5(str):
m = hashlib.md5()
m.update(str.encode('utf-8'))
return m.hexdigest()
def getRequestHeader(token=''):
headers = {
'User-Agent': 'duban-client.py, author:xuxiaobo',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'X-Forwarded-For' : '192.168.56.111',
}
return headers
def getRequestForm(token=''):
headers = {
}
return headers
def jsonStandFormat(jsondata):
return json.dumps(jsondata, sort_keys=True, indent=4, separators=(',', ':'), ensure_ascii=False)
def getFileContent(file):
fp = open(file, 'r', encoding='utf-8')
res = fp.read()
fp.close()
return res
def saveFileContent(file, content):
fp = open(file, 'w', encoding='utf-8')
fp.write(content)
fp.close()
def getFileContentb(file):
fp = open(file, 'rb')
res = fp.read()
fp.close()
return res
def saveFileContentb(file, content):
fp = open(file, 'wb')
fp.write(content)
fp.close()
def dictToUrlParams(data):
tmps = []
for k,v in data.items():
tmps.append('%s=%s' % (str(k), str(v)))
return '&'.join(tmps)
def sendRequest(subUrl, data, method='get', token = '', name = ''):
url = baseurl + subUrl
print("接口名称:%s" % name)
print("请求URL:%s" % url)
print("请求方式:%s" % method)
headers = getRequestHeader(token)
print("请求头:%s" % jsonStandFormat(headers))
odata = copy.deepcopy(data)
if odata.get('data'):
odata['data'] = json.loads(odata['data'])
print("请求参数:%s" % jsonStandFormat(odata))
if method == 'post':
res = requests.post(url, headers=headers, json=data)
else:
dataurl = dictToUrlParams(data) if data else ''
if '?' in url:
url = url+'&'+dataurl
else:
url = url+'?'+dataurl
res = requests.get(url, headers=headers, data=data)
res.encoding = res.apparent_encoding
print("原始响应:%s" % res.text)
try:
response = json.loads(res.text)
except:
response = {}
print("响应:%s" % jsonStandFormat(response))
print()
return response
def sendRequestForm(subUrl, data, method='get', token = '', name = ''):
url = baseurl + subUrl
print("接口名称:%s" % name)
print("请求URL:%s" % url)
print("请求方式:%s" % method)
headers = getRequestForm(token)
print("请求头:%s" % jsonStandFormat(headers))
print("请求参数:%s" % jsonStandFormat(data))
if method == 'post':
res = requests.post(url, headers=headers, data=data)
else:
dataurl = dictToUrlParams(data)
if '?' in url:
url = url+'&'+dataurl
else:
url = url+'?'+dataurl
res = requests.get(url, headers=headers, data=data)
res.encoding = res.apparent_encoding
#print("原始响应:%s" % res.text)
try:
response = json.loads(res.text)
except:
response = {}
print("响应:%s" % jsonStandFormat(response))
print()
return response
def getToken(subUrl, data, method='get', token = '', name = ''):
url = baseurl + subUrl
headers = getRequestHeader(token)
if method == 'post':
res = requests.post(url, headers=headers, json=data)
else:
dataurl = dictToUrlParams(data)
if '?' in url:
url = url+'&'+dataurl
else:
url = url+'?'+dataurl
res = requests.get(url, headers=headers, data=data)
res.encoding = res.apparent_encoding
try:
response = json.loads(res.text)
except:
response = {}
return response
if __name__ == '__main__':
query = '''
query {
laoshis(searchStr: "") {
id, name, age
}
}
'''
data = {
"query": query
}
res = sendRequestForm('/', data, 'post', token, '测试无参数的情况')
query = '''
query {
laoshis(searchStr: "哥") {
id, name, age
}
}
'''
data = {
"query": query
}
res = sendRequestForm('/', data, 'post', token, '测试有参数的情况')
query = '''
query {
laoshis(searchStr: "哥") {
id, name
}
}
'''
data = {
"query": query
}
res = sendRequestForm('/', data, 'post', token, '测试有参数少列的情况')
运行结果:
服务端:

客户端:
接口名称:测试无参数的情况
请求URL:http://127.0.0.1:5000/
请求方式:post
请求头:{}
请求参数:{
"query":"\n query {\n laoshis(searchStr: \"\") {\n id, name, age\n }\n }\n "
}
响应:{
"laoshis":[
{
"age":30,
"id":"TGFvc2hpT2JqZWN0VHlwZTox",
"name":"老师1"
},
{
"age":31,
"id":"TGFvc2hpT2JqZWN0VHlwZToy",
"name":"老师2"
},
{
"age":32,
"id":"TGFvc2hpT2JqZWN0VHlwZToz",
"name":"老师3"
},
{
"age":11,
"id":"TGFvc2hpT2JqZWN0VHlwZTo0",
"name":"哈哈姐"
},
{
"age":22,
"id":"TGFvc2hpT2JqZWN0VHlwZTo1",
"name":"李淳风"
},
{
"age":21,
"id":"TGFvc2hpT2JqZWN0VHlwZTo2",
"name":"三哥"
},
{
"age":23,
"id":"TGFvc2hpT2JqZWN0VHlwZTo3",
"name":"大黑"
},
{
"age":34,
"id":"TGFvc2hpT2JqZWN0VHlwZTo4",
"name":"盛赞哥"
}
]
}
接口名称:测试有参数的情况
请求URL:http://127.0.0.1:5000/
请求方式:post
请求头:{}
请求参数:{
"query":"\n query {\n laoshis(searchStr: \"哥\") {\n id, name, age\n }\n }\n "
}
响应:{
"laoshis":[
{
"age":21,
"id":"TGFvc2hpT2JqZWN0VHlwZTo2",
"name":"三哥"
},
{
"age":34,
"id":"TGFvc2hpT2JqZWN0VHlwZTo4",
"name":"盛赞哥"
}
]
}
接口名称:测试有参数少列的情况
请求URL:http://127.0.0.1:5000/
请求方式:post
请求头:{}
请求参数:{
"query":"\n query {\n laoshis(searchStr: \"哥\") {\n id, name\n }\n }\n "
}
响应:{
"laoshis":[
{
"id":"TGFvc2hpT2JqZWN0VHlwZTo2",
"name":"三哥"
},
{
"id":"TGFvc2hpT2JqZWN0VHlwZTo4",
"name":"盛赞哥"
}
]
}
本文来自博客园,作者:河北大学-徐小波,转载请注明原文链接:https://www.cnblogs.com/xuxiaobo/p/18987759

浙公网安备 33010602011771号