· 4 min de leitura

Crie uma API GraphQL sobre o Swoole

Estou assumindo que você já sabe o que são GraphQL e Swoole, então que tal irmos direto para o código?

Estou assumindo que você já sabe o que são GraphQL e Swoole, então que tal irmos direto para o código?

O que talvez você ainda não conheça é o Siler! Ele é um conjunto de abstrações de alto nível e propósito geral que busca oferecer uma API para programação declarativa em PHP.

Com o Siler, podemos abstrair as partes mais “difíceis” de ferramentas populares como GraphQL e, mais recentemente, Swoole. E sim, eu sou o autor, então fique à vontade para abrir issues ou fazer perguntas sobre ele.

“Falar é fácil, mostre-me o código”. Vamos lá!

Quero deixar isto o mais simples possível para podermos focar em usar GraphQL e Swoole através do Siler, em vez de resolver problemas difíceis de domínio e regra de negócio. Por isso, vamos implementar uma boa e velha lista de tarefas.

$ mkdir todos
$ cd todos/

Não sei você, mas eu gosto muito de começar um projeto do zero, em um terreno limpo, em vez de usar boilerplate ou código de esqueleto.

$ composer require leocavalcante/siler
$ composer require webonyx/graphql-php
$ composer require --dev swoole/ide-helper

Essas são nossas dependências. O Siler em si não reimplementa um parser/executor GraphQL; ele constrói sobre o trabalho atual da Webonyx. O mesmo vale para o Swoole, claro, então garanta que a extensão Swoole esteja instalada e funcionando no seu ambiente PHP.

O schema

Um Todo é simples: precisamos de um ID para identificá-lo de forma única, um título para funcionar como uma descrição curta, um corpo para funcionar como uma descrição completa e uma flag para indicar se ele já foi concluído.

https://medium.com/media/2e88bfd9a29510097ef679b0a71f49ba/href

Também precisamos de um tipo para funcionar como Input e, claro, se você conhece GraphQL, de um tipo Query para consultar Todos e de um tipo Mutation para criá-los, alterá-los e removê-los. Aqui está nosso schema completo:

https://medium.com/media/26b96d722cec48bc9aa61fd9ae544465/href

É isso! Vamos então para o PHP.

O servidor

Mais uma vez, assumindo que você já sabe, mas… usando Swoole, construímos nosso próprio servidor HTTP, assim como no Node.js. É uma boa, não é?

https://medium.com/media/be55c26f415cf5ff2ca4f00d8886d0cc/href

Você provavelmente viu algo diferente na documentação do Swoole. Isso é o Siler trabalhando! Deixando tudo ainda mais simples e agradável. Como funções PHP comuns, mas pegando emprestado o máximo possível de pureza, imutabilidade e funções de alta ordem do paradigma de Programação Funcional.

Inicie o servidor usando php index.php, acesse http://localhost:8000 (ou qualquer porta que você sobrescrever usando a variável de ambiente PORT) e confira se está funcionando.

O domínio

Agora é hora de trabalhar no nosso domínio.

Primeiro definimos nosso módulo Todos. É o módulo que vai conter as funções que trabalham em um Todo. Eu sei, isso não é muito orientado a objetos, mas eu realmente não me importo, não quero seguir por esse caminho. Podemos trabalhar nisso usando qualquer paradigma que você preferir; você verá que ele não está acoplado ao restante do código.

https://medium.com/media/4a6af67ad9bf9c50759a627b45ad2a4d/href

Por enquanto, é isso que vamos fazer: find e save. find pode receber um Criteria; é assim que você pode construir várias formas diferentes de consultar um Todo. Eles são simples:

https://medium.com/media/e45cbd933bfe6d0c646809484bde3d68/href

A aplicação

Não estou tentando fazer DDD aqui, mas é um conceito legal, certo? Depois de definir nosso domínio, estamos prontos para passar para a próxima camada e começar a construir a camada de aplicação. Nada mais limpo e útil para testes do que uma implementação em memória de algum I/O.

https://medium.com/media/c499d0f0fe5e22551e7060775818b13b/href

Fica bem claro o que está acontecendo aqui, certo? Estamos buscando e salvando em um array em memória.

Ter a interface Todos e trabalhar em suas implementações abre uma grande variedade de possibilidades, desde testes usando implementações em memória até trabalho real com implementações em PDO ou NoSQL. Isso vai ficar mais claro agora quando você vir como os Resolvers são construídos:

Os resolvers

https://medium.com/media/09ecbbec0ecb5186e18c4ca76a7282a8/href

O resolver de Query basicamente vincula um Criteria a um módulo Todos. Note que os dois resolvers dependem da abstração de um módulo Todos, não de uma implementação.

O resolver Save mostra um pouco mais de sua funcionalidade; talvez você os associe a um Controller do padrão MVC.

Agora precisamos juntar essas peças de uma forma que depois seja fácil dizer ao construtor do Schema qual resolver ele deve usar. Bem, que tal uma factory?

https://medium.com/media/3b939a3f82e95f81564e4f2635a22ac3/href

O servidor (atualização)

Nosso código-fonte está todo lá: nosso domínio, suas implementações e os resolvers funcionando como a aplicação. Agora é hora de conectar tudo isso ao servidor:

https://medium.com/media/0f0f3bffa0c35181542fd0447f647c86/href

E aí está nossa API GraphQL rodando sobre o Swoole com a ajuda do Siler!

Espero que você tenha gostado. Fique à vontade para fazer perguntas.

O código-fonte completo está disponível aqui.

Obrigado!