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

Оригинал

Другие материалы по теме:

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

admin
11 декабря 2018

ООП на Python: концепции, принципы и примеры реализации

Программирование на Python допускает различные методологии, но в его основе...
admin
23 февраля 2017

SQL за 20 минут

Предлагаем вашему вниманию статью с кричащим названием "SQL за 20 минут". К...
admin
13 февраля 2017

Программирование на Python: от новичка до профессионала

Пошаговая инструкция для всех, кто хочет изучить программирование на Python...