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 – очень классная вещь. Декларативный синтаксис делает его довольно простым в освоении и использовании. Он явно стоит вашего внимания.
Комментарии