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":"盛赞哥"
        }
    ]
}

  

posted @ 2025-07-16 16:06  河北大学-徐小波  阅读(277)  评论(0)    收藏  举报