Construindo um servidor GraphQL em minutos com a Siler PHP

GraphQL - uma query language como o SQL, mas desenhada para rodar no lado client

por Leo Cavalcante 04/04/2017 Comentários

Apresento-lhes:

GraphQL: uma query language como o SQL, mas desenhada para rodar no lado client, no caso: front-end.

Siler: uma biblioteca PHP que tem como diferencial simplificar o desenvolvimento evitando overheads.

GraphQL

A GraphQL trás, na verdade, uma nova abordagem pro desenvolvimento, ela praticamente faz uma inversão de quem fará a consulta aos dados, ou pelo menos, trás essa possibilidade pro lado client, o lado front-end, que antes era refém do que o back-end devolvia no JSON e principalmente a forma como esses dados estavam relacionados nesse JSON.

Graças à GraphQL, nós podemos trazer esse poder de consulta e interface de dados pro client.

É uma tecnologia desenvolvida pelo Facebook, caprichada pra funcionar com React, mas vai muito bem com outras bibliotecas JavaScript e até clients que não sejam o navegador como Android (Java) e iOS (Swift/Obj-C).

https://www.youtube.com/watch?v=9sc8Pyc51uU

Na especificação da GraphQL tem um conceito de extrema relevância pra tecnologia que é o sistema de tipos (Type System). Isso faz com que seus dados sejam forte e estaticamente “tipados”, algo bem diferente do que estamos acostumados com JSON e principalmente Percent-encoding (application/x-www-form-urlencoded) onde tudo é uma String. Mas isso é uma especificação e o lado que infere a implementação é o do servidor; então o que o PHP tá fazendo aqui, Léo? Bom, hoje o PHP 7 tem um sistema de declaração de tipos que pode até ser estrito dentro do seu projeto, mas a GraphQL não é sobre os tipos da linguagem que você implementa é sobre os tipos do seu endpoint, eles são normalmente implementados de acordo com seu domínio, suas entities (ou Models pra galera que curte um MVC).

Claro, você não precisa implementar do zero tipo primitivos escalares como Int, Float, String, Boolean e ID (se usar uma biblioteca descente). E existem tipos abstratos pra você usar como base na implementação dos seus próprios tipos como: Object, Interface e List.

Por falar em biblioteca descente, a Siler não implementa a GraphQL, ela é um wrapper da graphql-php, importante ressaltar isso e dar os devidos créditos.

Chega de “falar”. Bora pro código!

Vamos criar um projetinho PHP usando Composer e um template bem simples da Siler.

$ composer create-project siler/project siler-graphql

Caso não conheça o Composer, esse comando vai clonar o projeto leocavalcante/siler-project e depois executar composer install pra instalar as dependências, que nesse caso é só a Siler mesmo.

Como falei antes, a Siler não implementa a especificação da GraphQL, nela acompanha um wrapper/helper de uma biblioteca que já implementa essa especificação. Na Siler as dependências são explícitas, então vamos entrar no diretório do projeto e trazer a graphql-php:

$ cd siler-graphql
$ composer require webonyx/graphql-php

E agora nosso index.php vai ficar da seguinte forma:

<?php

use Siler\{
    Route,
    Http\Response,
    Functional as F,
    Graphql
};

require_once __DIR__.'/vendor/autoload.php';

$query = Graphql\type('Query')([
    Graphql\str('foo')(F\always('bar'))
]);

Response\header('Access-Control-Allow-Headers', 'content-type');
Response\header('Access-Control-Allow-Origin', 'http://localhost:3000');

Graphql\init(new \GraphQL\Schema([
    'query' => $query(),
]));

Não se assuste, vou explicar.

No primeiro bloco (3-8) estamos declarando o que iremos usar da Siler, como podem notar, ela não é só pra GraphQL, também abstrai HTTP e alguns conceitos de programação functional. E é bom deixar claro: estamos usando a notação agrupada da keyword use que veio com o PHP 7.

O que importa pra gente é 12-14 e 19-21, porque na 16 e 17 estamos apenas declarando alguns headers que irão na nossa resposta HTTP pro CORS funcionar direitinho.

No bloco 12-14 estamos declarando um novo tipo GraphQL, aquele comentado anteriormente, com a Siler é só questão de chamar uma função. Na Siler\Graphql\type nós declaramos um ObjectType de nome Query, ali pode ser qualquer nome que você queira dar pra Root Query do seu endpoint GraphQL. Essa função retorna outra função (porque programação funcional rulez) onde o primeiro argumento é um array de fields. Na linha 13 nós estamos declarando um novo field do tipo String e com mais um extra-help da Siler, passamos a função always que significa que vai retornar sempre esse mesmo valor (<code>bar</code>) independente dos argumentos que essa função for chamada (vide const do Haskell).

No bloco 19-21 nós estamos iniciando um novo endpoint que irá ouvir e interpretar a query de GraphQL que veio no request. Estamos prontos para testar a funcionalidade da nossa API e existe uma ferramenta excelente pra isso, onde podemos testar endpoints GraphQL com uma interface gráfica - seria o Postman do GraphQL - é do próprio Facebook e se chama GraphiQL!

Se você estiver com dificuldades para configurar seu app GraphiQL, pode dar uma olhada nesse projeto.

Com o GraphiQL rodando na 3000 (default do create-react-app) e a API na 8000 (default do siler/project). Podemos testar nosso endpoint com a premissa de que uma chamada pro field foo na Query o retorno deve ser bar:

Maravilha! Temos aí um Hello World de GraphQL com PHP em apenas 20 linhas de código.

Já tem muita informação pra um post só, que inclusive tá cheio de links pra você se aprofundar no assunto e descobrir que tem algo chamado mutations que seria a especificação para mudanças na GraphQL que não é feita só de consultas.

Se não aguenta esperar um próximo post e já sacou a ideia. Tem um trechinho no README da Siler com uma mutation que faz a soma de dois argumentos.

Espero que tenha se interessado pela GraphQL, IMHO é uma tecnologia divisora de águas trazendo esse conceito de queries pro front-end. Nós temos caminhado cada vez mais para soluções menos monolíticas onde o client e o server estão bem separados e essa é a “cola” que eles precisam!