В этом посте мы погрузимся в GraphQL с популярной библиотекой GraphQL для Python под названием Graphene.

Для начала вам необходимо установить Python в вашей среде. В большинстве ОС Linux уже должен быть установлен python. В противном случае используйте для установки диспетчер пакетов ОС. Для Windows или Mac OS есть пакеты, которые можно скачать с https://www.python.org.

GraphQL - это язык запросов, который устраняет ряд недостатков REST API. Я обсуждал эти моменты в предыдущем посте. Вы можете найти это здесь".

Установка необходимых пакетов

Pip - это менеджер пакетов для Python. Установить Graphene и Django легко с помощью pip. Если вы используете python 3.4 или более позднюю версию, pip уже должен быть установлен. В противном случае я рекомендую вам установить его через диспетчер пакетов вашей ОС или с помощью файла сценария get-pip.py.

Лучше поработать в виртуальной среде, чтобы установить дополнительные пакеты, чтобы основная установка python оставалась чистой и менее загроможденной. Теперь давайте создадим новую виртуальную среду и создадим в ней исходный код, как показано ниже.

$ mkdir graphene-api
$ cd graphene-api
$ python3 -m venv .
$ source bin/activate

Попав в виртуальную среду, мы можем установить Graphene и Django. Используйте приведенные ниже команды для установки.

$ pip install "graphene>=2.0"
$ pip install Django==3.17
$ pip install graphene-django

Первый код GraphQL

Добро пожаловать в GraphQL. Код, использующий библиотеку графена, очень прост. Помните, что Graphene - это библиотека, ориентированная сначала на код. Разработчик может сначала начать писать код, а не схему. Ниже приведен простой фрагмент этого кода. Создайте файл с именем schema_hello_query.py (вы можете использовать любое имя)

Поскольку мы пишем операцию запроса, она представлена ​​в виде класса Query в строке 4, который имеет тип graphene.ObjectType. Поле называется «welcome» в строке 5. Строка 7 - это функция преобразователя, которая вызывается при выполнении операции запроса welcome используется как в строках 14–16. Он принимает в качестве аргумента self и info и возвращает простую строку. Затем запрос регистрируется в схеме в строке 10.

Запрос, заключенный между 14–16, выполняется в строке 12, а ответ сохраняется в результате.

Строки 20–30 выводят ответ в разных форматах. Результат кода показан ниже.

$ python3 schema_query.py 
dict_items([('welcome', 'Welcome to GraphQL')])
-------------------------------------------
Welcome to GraphQL
-------------------------------------------
{"welcome": "Welcome to GraphQL"}
-------------------------------------------
{
  "welcome": "Welcome to GraphQL"
}

Запрос и изменение GraphQL

Поскольку запрос облегчает чтение в GraphQL, создание, обновление и удаление упрощаются с помощью мутаций. Ниже приведено расширение указанной выше простой программы, которое содержит сложный объект (с именем Course) в качестве поля в классе Query и несколько изменений.

Здесь у нас есть еще два поля (is_permitted и курсы) в строке 12 и 13 класса запроса соответственно. разрешено - логическое значение, а курсы - сложный объект, заданный как список. Тип курсы содержит id, имя и поля типа created_on, ID, String и DateTime.

В строке 40 в классе Mutation, определенном в строке 39, определена мутация create_course. Этот класс должен содержать все определенные мутации. В данном случае у нас только один. CreateCourse - это отдельный класс, в котором есть поле 'course' типа 'Course ». У него есть метод mutate, который принимает один аргумент с именем 'name' ('id' жестко запрограммирован по 7 здесь практически вы можете использовать генератор UUID для создания уникального идентификатора). Это используется для создания объекта Course. Созданный курс возвращается.

Обратите внимание, как запрос на мутацию между строками 103–111 принимает параметр, переданный с использованием словаря variable_values ​​. Такая же мутация без переданной переменной используется в мутации 89–97. Также запустите другие запросы, раскомментировав соответствующий блок schema.execute (убедитесь, что вы оставили нетронутым только один запрос, а другие оставили комментарии).

Также обратите внимание, что этот фрагмент поможет вам быстро проверить свои запросы и изменения. Созданный курс не сохраняется. Для этого нам понадобится какое-то упорство. Также запросы обычно выполняются на стороне клиента. Не в том же месте, что показано выше, где определены запросы и мутации, хотя могут быть случаи, когда это необходимо.

Написание GraphQL API с помощью Django и Graphene

Django - популярный фреймворк для веб-разработки на Python. Он использовался для разработки многих популярных веб-сайтов и веб-приложений. В этой статье я не собираюсь описывать основы Django. У него отличная документация и сообщество, так что вы можете начать работу с django с относительно меньшими усилиями. Я предполагаю, что у вас есть некоторый уровень понимания django. Вы все равно должны понимать, если вы не работали с django, но занимались веб-разработкой с использованием аналогичной среды, такой как Ruby on Rails, Laravel или Express.

Вы можете создать новую виртуальную среду, как указано ранее, и установить пакеты django, graphene-django, django-graphql-jwt, django-cors-headers. Создайте новую папку в виртуальной среде с именем по вашему выбору.

$ mkdir bookstore
$ cd bookstore
# Start a django project
$ django-admin startproject app
$ cd app/
$ ls
app       manage.py
$ python3 manage.py runserver
...
Django version 3.1.7, using settings 'app.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C

На этом этапе, если вы нажмете http://127.0.0.1:8000/ в браузере, вы должны увидеть домашнюю страницу django.

Мы собираемся смоделировать простое приложение книжного магазина для просмотра списка книг. API GraphQL предназначен для управления этим. В django рекомендуется создать приложение в созданной ранее папке главного проекта bookstore.

$ python3 manage.py startapp book
$ cd book/
$ ls
__init__.py admin.py    apps.py     migrations  models.py   tests.py    views.py

model.py - это файл, в котором вы определяете свою модель данных, которая будет отражаться в базовой базе данных. Django поддерживает множество баз данных, которые можно настроить в файле settings.py в основной папке app. По умолчанию он поставляется с sqlite3, который является отличной базой данных для тестирования. Это база данных на основе файлов, которая также подходит для встроенных приложений, таких как мобильные приложения.

Чтобы смоделировать книгу, мы можем использовать файл model.py, как показано ниже, для разработки атрибутов книги; название, автор и т. д. Это объектно-реляционное отображение (ORM) Django. Это создаст соответствующий SQL для создания таблиц и столбцов.

Модель также содержит ForeignKey для другой модели, обозначенной get_user_model (); модель User по умолчанию, поставляемая Django.

Вы можете найти полный рабочий образец проекта книжного магазина в github здесь. Я рекомендую вам клонировать репо и открыть его в VSCode или аналогичном, когда будете следовать.

Здесь вы увидите, помимо приложения books, у меня также есть папка user (а не app как книги app). Это просто папка с файлом schema.py.

Вы также увидите, что в файле settings.py приложение books указано в INSTALLED_APPS список. В дополнение к этому, приложение graphene_django также указано в INSTALLED_APPS.

После обновления файла models.py нам нужно выполнить две следующие команды, чтобы обновить базовую базу данных (или создать базу данных). Эти команды необходимо запускать в папке приложения, в которой находится файл manage.py. Первая команда должна создать db.sqlite3, если он еще не существует. И он будет создавать или изменять содержимое в папке migrations в приложении books и в любых других приложениях, в которых models.py изменено.

$ python3 manage.py makemigrations
Migrations for 'books':
  books/migrations/0001_initial.py
    - Create model Book
$ python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, books, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying books.0001_initial... OK
  Applying sessions.0001_initial... OK

У нас есть указанная модель, и теперь у нас должны быть запросы GraphQL для запроса элементов в базе данных, а также мутации для динамического добавления книг. Это указано в schema.py в приложении книги.

Если вы посмотрите в файл schema.py, у нас есть модель Book, импортированная и указанная в качестве атрибута модели. в классе Meta в DjangoObjectType классе с именем BookType . Затем в строках 12–25 определяется корневой тип запроса (клонируйте репо и откройте его в VSCode, чтобы изучить код).

Я также определил три мутации с именами create_book, update_book и delete_book в корневой мутации с соответствующими полями CreateBook (строка 27–46), UpdateBook (строки 48–73) и DeleteBook (строки 75–90) соответственно. У каждой мутации есть класс Аргументы, в котором указаны необходимые параметры. Они будут записаны в методе mutate () с параметром ** kwargs.

Точно так же в приложении user вы найдете файл schema.py с запросом и мутацией для пользователей. Однако в этой папке нет файла model.py, поскольку мы используем модель django User по умолчанию.

Эти отдельные запросы и изменения приложений объединяются в файле schema.py в папке приложения как базовые запросы и мутации. Этот файл указан в объекте GRAPHENE в атрибуте SCHEMA в settings.py как app.schema .schema.

В отличие от выполнения schema.execute (), как мы делали ранее с простым графеном, здесь для выполнения запросов GraphQL включена интерактивная IDE GraphQL. Вы сможете увидеть его в файле url.py.

Вы можете получить доступ к GraphiQL IDE, перейдя по адресу http://127.0.0.1:8000/graphql/ после запуска сервера, как показано ниже.

$ python3 manage.py runserver

Вы можете создать пользователя со следующей мутацией

mutation {
  createUser(username: "shazni", password:"shazni", email:"[email protected]") {
    user {
      id
      username
      email
    }
  }
}

Ответ будет иметь вид

{
  "data": {
    "createUser": {
      "user": {
        "id": "1",
        "username": "shazni",
        "email": "[email protected]"
      }
    }
  }
}

Вы можете запросить конкретного пользователя, как показано ниже.

)query {
  user(id: 1) {
    id
    email
    email
  }
}

Аутентификация

Проект также требует аутентификации для создания книг. Мутации защищены. Здесь включена аутентификация JWT. Вот почему нам потребовалось установить «django-graphql-jwt» раньше. Это также указано в разделе объектов MIDDLEWARE (django.contrib.auth.middleware.AuthenticationMiddleware) и GRAPHENE (graphql_jwt.middleware.JSONWebTokenMiddleware) в файл settings.py.

Кроме того, есть еще одна дополнительная настройка объекта в файле settings.py, как показано ниже.

AUTHENTICATION_BACKENDS = [
   'graphql_jwt.backends.JSONWebTokenBackend',
   'django.contrib.auth.backends.ModelBackend'
]

Чтобы включить аутентификацию, нам нужно добавить три мутации, которые позволят нам получить токен, проверить токен и обновить токен. Это указано в schema.py в разделе apps, в корневом разделе Mutation.

token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()

Используйте приведенный ниже запрос, чтобы получить действительный токен JWT. Вам необходимо указать существующего пользователя и пароль, чтобы получить действительный ответ.

mutation {
    tokenAuth(username:"shazni", password:"shazni") {
       token
    }
}

В результате должен получиться токен JWT, как показано ниже.

{
    "data": {
       "tokenAuth": {
           "token":  "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InNoYXpuaSIsImV4cCI6MTYxNDcwNTY3NSwib3JpZ0lhdCI6MTYxNDcwNTM3NX0.JOEfpeynrMm-CzbbMk2AAEM6h_IJukvSxpTnc3SH4YM"
       }
    }
}

Если вы посмотрите на файл schema.py в приложении books, в каждом методе преобразователя изменений, вы обнаружите ниже фрагмент, который проверяет подлинность. Это будет подтверждено только в том случае, если присутствует действительный токен JWT.

user = info.context.user
if user.is_anonymous:
    raise GraphQLError("user must logged in to create a book")

Теперь давайте создадим книгу. Используйте Postman для создания тестового примера с URL-адресом http: // localhost: 8000 / graphql / и используйте указанные ниже данные. Примечание. Почтальон теперь поддерживает GraphQL. Мы не можем использовать интегрированную среду GraphiQL IDE для передачи пользовательских заголовков в запросе. Следовательно, здесь мы используем Postman. Вы также можете использовать такое средство, как Бессонница.

mutation {
  createBook(
    author: "GraphQL author", 
    title: "GraphQL in Action",
    description: "Get to know GraphQL"
    publisherBookUrl: "https://publisher.com/frameworks/web/graphql_in_action"){
    book {
      title
      author
      publisherBookUrl
      description
    }
  }
}

Если вы опустите заголовок авторизации, вы получите сообщение об ошибке «Пользователь должен войти в систему». Чтобы он заработал, вам нужно передать токен JWT в качестве заголовка.

Authorization: JWT <jwt_token>

Когда заголовок указан, мы сможем получить созданную Книгу с ответом ниже.

{
    "data": {
        "createBook": {
            "book": {
                "title": "GraphQL in Action",
                "author": "GraphQL author",
                "publisherBookUrl": "https://publisher.com/frameworks/web/graphql_in_action",
                "description": "Get to know GraphQL"
            }
        }
    }
}

Для запроса мы не указали необходимую аутентификацию. Таким образом, вы можете запрашивать все книги, как показано ниже, без заголовка авторизации.

query {
  books {
      id
      title
      author
      publisherBookUrl
      description
      releasedOn
  }
}

Ответ будет вроде.

{
    "data": {
        "books": [
            {
                "id": "1",
                "title": "GraphQL in Action",
                "author": "GraphQL author",
                "publisherBookUrl": "https://publisher.com/frameworks/web/graphql_in_action",
                "description": "Get to know GraphQL",
                "releasedOn": "2021-03-02T17:18:05.669126+00:00"
            }
        ]
    }
}

Теперь это рабочий пример API. Вот и все.

Вывод

GraphQL - это мощный язык запросов, который устраняет некоторые недостатки REST API. Появилось множество фреймворков и библиотек для множества языков программирования, поддерживающих GraphQL.

Python - не исключение. Сообщество Python выпустило такие библиотеки, как Graphene, Ariadne и Strawberry. Создать API с использованием Python с одной из этих библиотек очень просто. В этой статье мы рассмотрели рабочий пример с graphene-django для создания простого API.

Обновление: 13 марта 2021 г. - Эта ссылка представляет собой видеозапись с объяснением отдельных шагов, описанных выше.