Сравним GraphQL и библиотеку Graphene в Python
GraphQL – это стандарт декларирования структуры данных и способов получения данных, предложенный и реализованный Facebook.
GraphQL был создан для того, чтобы заменить Rest API. Он имеет встроенную документацию с приложением GraphiQL. С его помощью пользователи получают ответ во время того, как пишут запрос.
Основы
Основным представителем Python является небольшая библиотека под названием Graphene. Но прежде нужно поговорить о некоторых фундаментальных основах GraphQL:
- Модель – это объект, который определен с помощью GraphQL.
- Схема определяет модели и их атрибуты.
- Каждый атрибут модели имеет свой собственный преобразователь. Это функция, которая отвечает за получение данных для этого конкретного атрибута модели.
- Запрос – это то, что использует пользователь, дабы получить или отправить данные в GraphQL.
- Мутации – особые запросы, которые позволяют изменять данные конкретной модели или набора моделей.
- GraphiQL – пользовательский интерфейс, используемый для взаимодействия с сервером GraphQL.
Теперь по поводу Python
У библиотеки Graphene есть поддержка фреймворков, таких как Flask или Django. С помощью Graphene можно определить атрибуты модели, а также анализировать запросы. Задача этой библиотеки – превратить модели SQLAlchemy или Django в объекты GraphQL.
Разберемся с библиотекой Graphene
Установка библиотеки максимально проста. Она поддерживается и на 2, и на 3 версии Python.
pip install graphene
После установки нужно импортировать эту библиотеку:
import graphene # 1 class Query(graphene.ObjectType): # 2 hello = graphene.String(description='A typical hello world') # 3 def resolve_hello(self, args, context, info): # 4 return 'World' schema = graphene.Schema(query=Query) # 5 query = ''' query { hello } ''' # 6 result = schema.execute(query) # 7
В 1 строке мы импортируем пакет. Обратите внимание, что во 2 строке создается класс запроса. Все классы запросов наследуются от graphene.ObjectType. Также можно вставлять запросы в запросы. Кроме того, даже сложные объекты наследуются от graphene.ObjectType. Как правило, в классе содержатся все модели. Сейчас в нём находится только одна модель – hello. В 3 строке добавляем объект в схему. В данном случае это простая строка. В 4 пишем преобразователь для этой конкретной модели. В следующей объявляем схему и говорим ей, что query = Query. Затем вводим самый простой запрос и в 6-ой, 7-ой строках мы, наконец, выполним его. Вот как выглядит результат:
In [6]: result = schema.execute(query) In [7]: type(result) Out[7]: graphql.execution.base.ExecutionResult In [8]: result.data Out[8]: OrderedDict([('hello', 'world')])
Результат возвращается с тремя основными атрибутами: data, errors, invalid.
In [12]: result.data Out[12]: OrderedDict([('hello', 'world')]) In [13]: result.errors In [14]: result.invalid Out[14]: False
data возвращает нужные нам данные, errors указывают на возможные ошибки, invalid говорит о том, является ли запрос допустимым.
Основные типы
Теперь, когда мы получили представление об основах GraphQL, рассмотрим другие типы данных и начнём разбираться с более сложными объектами.
Существует много различных типов данных. Все они разделяются на скалярные и не скалярные. Скалярные являются базовыми типами объектов. Они могут быть строками, целыми числами, логическими значениями и т. д. Не скалярные – более сложными объектами. Часто они выступают в роли контейнеров скалярных типов данных. Например, списками. Они также могут быть интерфейсами, от которых наследуются другие типы объектов, и, конечно же, существуют типы мутаций, которые вносят изменения поверх данных.
Интеграция с помощью объектно-реляционного отображения
Graphene представляет из себя комбинацию библиотеки сериализации и интерпретатора запросов GraphQL, поэтому для него было бы разумно работать с ORM. На данный момент есть поддержка Django, SQLAlchemy, а также Google App Engine. Большинство из них довольно просто интегрировать.
Django
from django.db import models from graphene_django import DjangoObjectType class Account(models.Model): birth_date = models.DateField(db_column='personbirthdate', null=True) created_date = models.DateTimeField(blank=True, null=True, db_column='createddate') is_paying_customer = models.NullBooleanField(db_column='iscustomer') country = models.CharField(db_column='country', max_length=3, null=True, blank=True) customer_number = models.CharField( db_column='cnumber', unique=True, max_length=255, blank=True, null=True, editable=False) class Meta: managed = False db_table ='accountinfo' class AccountType(DjangoObjectType): class Meta: model = Account
Теперь можно использовать AccountType так же, как и любой другой объект. Вам даже не придется вручную добавлять объекты запроса. Если у вас установлен Django-фильтр, можно добавить graphene.Node в список интерфейсов для определенного типа. Это позволит объявить некоторые переменные в метаклассе, которые позволят типу быть легко интегрированным в запрос с помощью DjangoConnectedFilterField. Вот пример того, как это будет выглядеть с точки зрения модели Account:
class AccountNode(DjangoObjectType): class Meta: model = Account interfaces = (graphene.Node, ) filter_fields = [ 'customer_number', 'is_paying_customer', ]
Как это будет выглядеть в объекте запроса:
from graphene_django.filter import DjangoConnectedFilterField class AccountQuery(graphene.AbstractType): # Gives you a particular account account = graphene.Node.Field(AccountNode) # Gives you all the accounts available all_accounts = DjangoFilterConnectionField(AccountNode, order_by='-customer_number')
Это действительно упрощает весь процесс запроса. Обратите внимание на то, что graphene.AbstractType используется для объекта AccountQuery. Вот как это выглядит:
from .queries import AccountQuery class Query(AccountQuery, graphene.ObjectType): pass schema = graphene.Schema(query=Query)
Таким образом, основной объект запроса не будет загроможден, и можно будет продолжать добавлять запросы. Обязательно следует добавить graphene.ObjectType в качестве последнего аргумента для наследования, иначе конечный объект запроса не будет конкретным.
SQLAlchemy и другие
С SQLAlchemy можно просто использовать SQLAlchemyObjectType вместо DjangoObjectType. То же самое истинно и для Google App Engine.
Интеграция с помощью фреймворков
Вот как выглядит приложение Flask GraphQL:
from flask import Flask from flask_graphql import GraphQLView from models import db_session from schema import schema, Department app = Flask(__name__) app.debug = True app.add_url_rule( '/graphql', view_func=GraphQLView.as_view( 'graphql', schema=schema, graphiql=True ) ) @app.teardown_appcontext def shutdown_session(exception=None): db_session.remove() if __name__ == '__main__': app.run()
Подведем итоги по GraphQL
В общем и целом, GraphQL – очень классная вещь. Декларативный синтаксис делает его довольно простым в освоении и использовании. Он явно стоит вашего внимания.