This content originally appeared on Twilio Blog and was authored by Luís Leão
GraphQL é uma linguagem de manipulação e consulta de dados de código aberto para APIs em tempo de execução para atender a consultas com dados existentes. Essa linguagem foi desenvolvida internamente pelo Facebook em 2012 antes de ser lançada publicamente em 2015. Ela permite que os clientes definam a estrutura dos dados solicitados, e a mesma estrutura dos dados é retornada do servidor, evitando assim que dados desnecessários sejam retornados.
O GraphQL tem três operações principais: Consultas para leitura de dados, Mutações para gravação de dados e Assinaturas para recebimento automático de atualizações de dados em tempo real. Um servidor GraphQL fornece aos clientes um esquema predefinido, um modelo dos dados que podem ser solicitados. O esquema serve como um terreno comum entre o cliente e o servidor.
Neste tutorial, usaremos Graphene, um framework GraphQL para Python, para criar uma API Django que usa consultas e mutações.
Requisitos do tutorial
Para acompanhar este tutorial, você deve ter os seguintes itens:
- Python 3.6 ou mais recente.
- Virtualenv, para criar um ambiente virtual para o projeto tutorial.
- Postman, para enviar solicitações à nossa API.
- Um conhecimento prático do framework web do Django .
Configuração do projeto
Começaremos criando um ambiente virtual e instalando os pacotes Python necessários.
Crie uma pasta para o nosso projeto:
mkdir django_graphql
cd django_graphql
Em seguida, crie um ambiente virtual Python e ative-o. Se você estiver seguindo este tutorial no Windows:
$ virtualenv env
$ env\Scripts\activate
Se você estiver usando um computador MacOs ou um Unix:
$ virtualenv env
$ source env/bin/activate
Instale as dependências necessárias para nosso projeto:
(env) $ pip install django graphene-django
Crie um novo projeto Django:
(env) $ django-admin startproject books_api
Altere seu diretório atual para o projeto:
(env) $ cd books_api
Crie um app api
no projeto books_api
(env) $ python manage.py startapp api
Em seguida, registre o app api
e integre o app de terceiros graphene-django
que instalamos anteriormente em nosso projeto books_api
. Encontre a lista INSTALLED_APPS
em books_api/settings.py
e adicione api
e "graphene-django" no final:
INSTALLED_APPS = [
...
'api',
'graphene_django',
]
Enquanto estiver em books_api/settings.py
, vá até o final do arquivo e adicione um dicionário GRAPHENE
com configurações para o pacote graphene-django
:
GRAPHENE = {
"SCHEMA": "api.schema.schema"
}
A configuração do SCHEMA
informa a Graphene onde encontrar o esquema GraphQL para o aplicativo. Definiremos o esquema depois que o banco de dados for criado.
Modelo de banco de dados
Abra o arquivo api/models.py
e digite o código abaixo para adicionar o modelo de banco de dados Book
:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
year_published = models.CharField(max_length=10)
review = models.PositiveIntegerField()
def __str__(self):
return self.title
Em seguida, crie e execute as migrações para nosso banco de dados:
$ python manage.py makemigrations
$ python manage.py migrate
Para ajudar a testar esse projeto, podemos preencher nosso banco de dados com alguns dados. Para fazer isso, crie um arquivo data.json
no diretório do projeto onde está o arquivo manage.py
e copie os seguintes dados nele:
[
{
"model": "api.book",
"pk": 1,
"fields": {
"title": "The One Thing",
"author": "",
"year_published": 2002,
"review": 3
}
},
{
"model": "api.book",
"pk": 2,
"fields": {
"title": "Python Crash Course",
"author": "Eric Matthes",
"year_published": 2015,
"review": 5
}
},
{
"model": "api.book",
"pk": 3,
"fields": {
"title": "Atomic Habits",
"author": "James Clear",
"year_published": 2002,
"review": 4
}
},
{
"model": "api.book",
"pk": 4,
"fields": {
"title": "The Compound Effect",
"author": "Darren Hardy",
"year_published": 2010,
"review": 3
}
},
{
"model": "api.book",
"pk": 5,
"fields": {
"title": "Clean Code",
"author": "Robert Cecil Martin",
"year_published": 2008,
"review": 4
}
}
]
Com o arquivo data.json
salvo no diretório atual, execute o comando abaixo para importar os dados para o banco de dados:
$ python manage.py loaddata data.json
Installed 5 object(s) from 1 fixture(s)
Em seguida, adicione o endpoint GraphQL ao final do dicionário urlpatterns
no arquivo books_api/urls.py
:
from django.contrib import admin
from django.urls import path
from graphene_django.views import GraphQLView
urlpatterns = [
path('admin/', admin.site.urls),
path('graphql', GraphQLView.as_view(graphiql=True)),
]
Crie uma API Books com GraphQL
Nesta seção, criaremos uma API com Graphene usando queries (consultas) e mutations (mutações) GraphQL.
Implemente um esquema GraphQL
Crie um novo arquivo na pasta api/schema.py
:
import graphene
from graphene_django import DjangoObjectType, DjangoListField
from .models import Book
class BookType(DjangoObjectType):
class Meta:
model = Book
fields = "__all__"
class Query(graphene.ObjectType):
all_books = graphene.List(BookType)
book = graphene.Field(BookType, book_id=graphene.Int())
def resolve_all_books(self, info, **kwargs):
return Book.objects.all()
def resolve_book(self, info, book_id):
return Book.objects.get(pk=book_id)
Nesta etapa, criamos duas classes, a primeira é BookType
, que adapta o modelo Book
a um DjangoObjectType
. Definimos fields
(campos) como __all__
para indicar que queremos todos os campos do modelo disponíveis em nossa API.
A classe Query
define as consultas GraphQL que a API fornecerá aos clientes. A consulta all_books
retornará uma lista de todas as instâncias BookType
, enquanto a consulta book
retornará uma instância BookType
fornecida por um ID de número inteiro. A classe define dois métodos, que são os "resolvers" (resolvedores) da consulta. Cada query (consulta) no schema (esquema) é mapeada para um método resolver (resolvedor).
Os dois resolvers (resolvedores) de query (consulta) consultam o banco de dados usando o modelo Django para executar a query (consulta) e retornar os resultados.
Adicione atualizações de dados com mutações em GraphQL
Agora, vamos adicionar operações de criação, atualização e exclusão por meio de mutações. Ainda no arquivo api/schema.py
, adicione o código abaixo na parte inferior:
class BookInput(graphene.InputObjectType):
id = graphene.ID()
title = graphene.String()
author = graphene.String()
year_published = graphene.String()
review = graphene.Int()
A classe BookInput
define campos semelhantes ao nosso objeto de modelo Book para permitir que o cliente adicione ou altere os dados por meio da API. Usaremos essa classe como argumento para nossas classes de mutação.
Vamos adicionar uma mutação para criar novos livros. Adicione o seguinte código na parte inferior de api/schema.py
:
class CreateBook(graphene.Mutation):
class Arguments:
book_data = BookInput(required=True)
book = graphene.Field(BookType)
@staticmethod
def mutate(root, info, book_data=None):
book_instance = Book(
title=book_data.title,
author=book_data.author,
year_published=book_data.year_published,
review=book_data.review
)
book_instance.save()
return CreateBook(book=book_instance)
A classe CreateBook
será usada para criar e salvar novas entradas de Book
no banco de dados. Para cada classe de mutação devemos ter uma classe interna Arguments
e um método de classe mutate()
.
Definimos uma instância da classe BookInput
que criamos anteriormente como nossos argumentos e a tornamos obrigatória com a opção required=True
. Depois disso, definimos o modelo com o qual estamos trabalhando com book = graphene.Field(BookType)
.
No método mutate
estamos salvando um novo livro chamando o método save()
em uma nova instância Book
criada a partir dos valores book_data
passados como argumento.
Abaixo, você pode ver a implementação da mutação UpdateBook
. Adicione este código na parte inferior da api/schema.py
:
class UpdateBook(graphene.Mutation):
class Arguments:
book_data = BookInput(required=True)
book = graphene.Field(BookType)
@staticmethod
def mutate(root, info, book_data=None):
book_instance = Book.objects.get(pk=book_data.id)
if book_instance:
book_instance.title = book_data.title
book_instance.author = book_data.author
book_instance.year_published = book_data.year_published
book_instance.review = book_data.review
book_instance.save()
return UpdateBook(book=book_instance)
return UpdateBook(book=None)
A classe de mutação UpdateBook
é muito semelhante a CreateBook
. A diferença aqui é a lógica no método mutate()
, que recupera um objeto do banco de dados pelo ID
de livro fornecido e, em seguida, aplica as alterações do argumento de entrada nele.
Finalmente, vamos adicionar uma mutação de exclusão. Adicione o código a seguir na parte inferior de api/schema.py
:
class DeleteBook(graphene.Mutation):
class Arguments:
id = graphene.ID()
book = graphene.Field(BookType)
@staticmethod
def mutate(root, info, id):
book_instance = Book.objects.get(pk=id)
book_instance.delete()
return None
Na classe de mutação DeleteBook
, temos graphene.ID
como o único argumento. O método mutate()
usa essa id para remover o livro referenciado do banco de dados.
Agora temos duas consultas e três mutações definidas. Para registrá-los na Graphene, adicione o código abaixo no final de api/schema.py
:
class Mutation(graphene.ObjectType):
create_book = CreateBook.Field()
update_book = UpdateBook.Field()
delete_book = DeleteBook.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
Teste a API GraphQL
Ainda não estamos prontos para testar a API. Vamos iniciar o servidor Django:
$ python manage.py runserver
Agora, acesse http://127.0.0.1:8000/graphql
no seu navegador. Você deve ver a interface GraphIQL para testes interativos da API GraphQL.
A seta preta no diagrama acima é onde você insere seu código GraphQL. Em seguida, clique no botão de reprodução no canto superior esquerdo da tela para executar o código e obter um resultado na área indicada com a seta azul.
Emita uma consulta
As consultas são usadas para solicitar dados do servidor. O código GraphQL abaixo está solicitando todos os livros do banco de dados. Insira-o no painel esquerdo da interface GraphIQL.
query {
allBooks {
id
title
author
yearPublished
review
}
}
Pressione o botão de reprodução para executar a consulta e ver os resultados no painel do lado direito.
Em seguida, tente a consulta a seguir, que solicita um único livro por seu id:
query {
book(bookId: 2) {
id
title
author
}
}
Observe como cada consulta pode especificar quais atributos do modelo de livro precisam ser retornados.
Crie um livro
O seguinte fragmento de GraphQL define uma mutação que adiciona um novo livro ao banco de dados:
mutation createMutation {
createBook(bookData: {title: "Things Apart", author: "Chinua Achebe", yearPublished: "1985", review: 3}) {
book {
title,
author,
yearPublished,
review
}
}
}
Atualize um livro existente
A próxima mutação GraphQL atualiza o livro com id=6
:
mutation updateMutation {
updateBook(bookData: {id: 6, title: "Things Fall Apart", author: "Chinua Achebe", yearPublished: "1958", review: 5}) {
book {
title,
author,
yearPublished,
review
}
}
}
Exclua um livro
O exemplo de mutação final exclui o livro com id=6
do banco de dados:
mutation deleteMutation{
deleteBook(id: 6) {
book {
id
}
}
}
Teste a API Book com outros clientes GraphQL
O Django CSRF impede que usuários não autenticados no site executem ataques mal-intencionados. Diante disso, qualquer solicitação POST feita em um aplicativo externo fora do site do Django resultará em um 403 Forbidden Error
.
Para evitar isso, há duas opções. A opção mais segura é adicionar o token CSRF gerado pelo aplicativo Django às solicitações POST
que seu cliente faz ao endpoint GraphQL. Consulte a seção Ajax na documentação do Django para saber mais sobre essa opção.
Uma opção mais fácil, porém menos segura, é isentar o endpoint GraphQL da proteção CSRF. Para fazer isso, abra o arquivo api/urls.py
e altere a definição do endpoint GraphQL da seguinte forma:
from django.urls import path
from graphene_django.views import GraphQLView
from django.views.decorators.csrf import csrf_exempt
urlpatterns = [
...
path('graphql', csrf_exempt(GraphQLView.as_view(graphiql=True))),
]
O wrapper csrf_exempt
adicionado ao GraphQLView
remove a verificação de token CSRF do endpoint.
Se você quiser ter certeza de que a proteção CSRF não interfere com seu endpoint GraphQL, você pode usar o Postman para enviar solicitações de GraphQL para a API Django:
Usando a captura de tela acima como referência, siga estas etapas para enviar uma solicitação de GraphQL com o Postman:
- Cole seu endpoint do GraphQL
http://127.0.0.1:8000/graphql
na caixa com a seta roxa. - Clique na primeira seta branca apontando para a opção"Body" (corpo)
- Clique nas opções de GraphQL na segunda seta branca
- Cole o código de consulta na caixa de consulta e clique no botão azul "Send" (Enviar).
- Você verá o resultado de sua solicitação de API na parte inferior, na área de seta verde-clara.
- Observe a área de seta azul, onde você deve fazer uma solicitação GET para consultas, ou uma solicitação POST para mutações.
Experimente os trechos de código que usamos acima para testar nossa API por meio do Postman.
Conclusão
Neste tutorial, criamos uma API simples de GraphQL no Django usando o pacote Graphene-Django criado sobre Graphene, que facilitou a adição da funcionalidade GraphQL ao nosso aplicativo Django.
Criamos consultas para ler dados, mutações para gravar e alterar dados e testamos nossa API usando a interface GraphIQL fornecida pela biblioteca Graphene-Django e pelo popular cliente de API Postman. Você pode encontrar o código completo do projeto aqui.
Este artigo foi traduzido do original "Building GraphQL APIs in Django with Graphene". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.
This content originally appeared on Twilio Blog and was authored by Luís Leão
Luís Leão | Sciencx (2021-07-08T20:00:01+00:00) Crie APIs GraphQL em Django com Graphene. Retrieved from https://www.scien.cx/2021/07/08/crie-apis-graphql-em-django-com-graphene/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.