Coding / Programming Videos

Post your favorite coding videos and share them with others!

GraphQL simples e testável com Django e Graphene – Juntos Somos Mais – Medium

Source link

Abandone REST de vez, ou nem tanto

Primeiramente, caso queira pular direto para o projeto com código testável e tudo mais, já deixo aqui o repositório:

E além disso, caso queira ver um exemplo do criador do framework, com outras situações como uso massivo do Relay:

A postagem exige um conhecimento básico de GraphQL, mas, assim como eu, acredito que você possa aprender testando um projeto pronto ou criando um seu do zero, em vez de ficar só na teoria, contudo é importante testar e ler materiais por fora, como as diversos links de ajuda que coloquei no final.

Pense em algo poderoso. Poder bélico!

Aproveitando o que já temos no Django

Normalmente Django é usado quando é necessário ter persistência de dados, logo temos os models com os mapeamentos necessários. Exemplo:

class Category(models.Model):
name = models.CharField(max_length=100, unique=True)

def __str__(self):
return self.name

Pra reaproveitar todos os campos mapeados com Graphene, é só criar uma classe que herde de DjangoObjectType (note que ele é uma extensão de ObjectType), seguindo nosso exemplo, marcaremos a nossa Category dentro da inner class Meta no atributo model:

class CategoryType(DjangoObjectType):
class Meta:
model = Category

Com o tipo definido em função da nossa model, agora precisamos criar um outro para especificar a query com seu respectivo resolver. Exemplo para retornar todas as categorias:

class QueryDefinition:
all_categories = graphene.List(CategoryType)

def resolve_all_categories(self, info, **kwargs):
return Category.objects.all()

Veja que a convenção é, com a query definida, no nosso caso all_categories, o seu respectivo resolver deve ser uma função Python cujo nome comece com resolve_ seguido no nome da query, logo fica resolve_all_categories. Uma observação, caso queira manter a retrocompatibilidade com Python 2.x, a QueryDefinition deve estender de object (motivos aqui).

Agora basta criarmos uma outra classe que herde da nossa QueryDefinition e de graphene.ObjectType, e fecharmos nosso schema.

class Query(QueryDefinition, graphene.ObjectType):
passschema = graphene.Schema(query=QueryDefinition)

E finalmente usarmos no módulo urls e rodar o projeto.

Veja que usamos a opção graphiql=True, isso habilita a ferramenta na request path api/graphql para testes!

Ou via cURL (não esqueça de desabilitar CSRF):

curl -X POST 
http://127.0.0.1:8000/api/graphql/
-H 'Accept: application/json'
-H 'Content-Type: application/json'
-d '{
"query": "query { allCategories { id name }}",
"variables": null
}'

Integração com DRF: CREATE e UPDATE prontos

Quando o projeto já contempla uso do DRF, com seus serializers e views, é tranquilo integrar também, é tão plug&play quanto é com model.

Bom, supondo o seguinte serializer:

class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ("id", "name")

Temos o correspondente no Graphene:

class CategorySerializerMutation(SerializerMutation):
class Meta:
serializer_class = CategorySerializer

É bom deixar claro que SerializerMutation nada mais é que um ObjectType também. Veja que simplesmente foi criado uma abstração para integração com o DRF, enfim, agora temos que definir a lista de mutations, assim como é feito para as queries:

class Mutations(graphene.ObjectType):
create_or_update_category = CategorySerializerMutation.Field()

E por fim referenciarmos no schema:

schema = graphene.Schema(query=QueryDefinition, mutation=Mutations)

Podemos criar uma categoria:

E atualizá-la também:

Como implementar delete, queries específicas e autenticação

Bom, aí entendo que a postagem fica muito grande. Recomendo ver como eu fiz o projeto de playground a deleção e debugar para entender as regras do framework. Fique tranquilo, tanto a deleção quanto query específica e autenticação são simples 🙂

Considerações finais

Achei bem mais prático que REST e até mais rápido no sentido de me fazer focar mais na regra de negócio em si do que na infraestrutura da API como por exemplo definir roteamento de endpoints, desenhar contratos, fixar como é o payload, query strings e afins, afinal, o schema do GraphQL é tipado e permite a resolução da integração 100% via interface front-end com autocomplete:

Para o integrador interessado na sua plataforma, fica mais fácil ele entender os limites da integração, consumir somente aquilo que ele precisa (especificando quais campos efetivamente ele quer no retorno) e até no consumo em si do GraphQL server, uma vez que o client de comunicação e transação dispensa a criação manual de SDKs.

O trade-off pesado, talvez, seja o aprendizado da tecnologia e até a confiança nela em função de qual linguagem está sendo usado. Confesso que tenho um certo receio com Python pois é notável ver que quase todos os repositórios do GraphQL Python (graphql-core, graphene, graphene-django, gql, etc.) estão meio parados considerando as issues abertas e as PRs, embora tenha uma certa tímida movimentação. Se fosse com JS, a conversa já seria diferente.

Pensando na exposição de um serviço nosso para o mundo com GraphQL, talvez seja complicado a adoção de um interessado, pois, novamente, existe a curva de aprendizado, então provavelmente continuaremos usando REST por um bom tempo, ou simplesmente, pensando em endpoints declarativos e específicos, REST ainda possa ser a melhor escolha sobre GraphQL, mas questiono até isso depois de aprender um cadinho dela.

Links úteis:

Caso queira saber de alguém que usou GraphQL para Python e tenha um consolidado de lições aprendidas, segue um testemunho sensacional da Verve:

Ao som da narração do Milton Leite, comentários do Casa Grande, jogo Corinthians versus Oeste de Barueri.

Source link

Bookmark(0)
 

Leave a Reply

Please Login to comment
  Subscribe  
Notify of
Translate »