O GraphQL tem um grande potencial na forma como os aplicativos voltados para o cliente solicitam dados, evitando o gerenciamento de grandes quantidades de cargas úteis desnecessárias e recuperando apenas o que realmente importa. Para esta postagem no blog, mostrarei como criar uma aplicação Laravel.

O que é GraphQL?

Uma Query Language. Infelizmente é uma resposta simples e pouco objetiva. Mesmo que GraphQL em si seja algo simples, por vários motivos a explicação do que ele é não é a mais simples.

Instalando e configurando dependências

Antes de tudo vamos antes configurar algumas dependências:

Criando um projeto Laravel

Vamos começar um novo projeto com o comando:

composer create-project laravel/laravel graphql-laravel

Se você não possui o composer instalado clique aqui para instalar.

Instalando o Sail

Laravel Sail é uma interface de linha de comando para interagir com o ambiente de desenvolvimento Docker padrão do Laravel. O Sail fornece um ótimo ponto de partida para criar um aplicativo Laravel usando PHP, MySQL e Redis sem exigir experiência prévia do Docker.

Em sua essência, Sail é o arquivo docker-compose.yml, o script de navegação fornece uma CLI com métodos convenientes para interagir com os contêineres do Docker definidos pelo arquivo docker-compose.yml.

Vamos instalar o Sail como uma dependência de desenvolvimento com:

composer require laravel/sail --dev

Como estamos usando o docker para executar o ambiente de desenvolvimento, precisamos de um Dockerfile, certo? Para ter acesso a este arquivo docker, e após instalar a dependência sail do comando anterior, você precisa executar o comando sail:install.

php artisan sail:install

O comando irá perguntar qual banco de dados você irá utilizar, basta escolher uma e pressionar enter.

E pronto, já podemos rodar nossa aplicação com o Sail utilizando o comando:

./vendor/bin/sail up -d

Para facilitar o uso do Sail e não termos de rodar o comando ./vendor/bin/sail up -d toda vez podemos adicionar um alias para facilitar o comando, para fazer isso basta adicionar a linha abaixo no seu arquivo do bash (~/.bashrc ou ~/.zshrc ).

alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'

E então podemos rodar o Sail com:

sail up -d

Ou pará-lo com :

sail stop

Instalando o Lighthouse

O Lighthouse é um pacote para Laravel que vai nos ajudar a criar uma API GraphQL.

Vamos começar instalando:

sail composer require nuwave/lighthouse

E publicamos o schema padrão em graphql/schema.graphql:

sail artisan vendor:publish --tag=lighthouse-schema

E também o arquivo de configuração do Lighthouse:

sail artisan vendor:publish --tag=lighthouse-config

O arquivo será criado em config/lighthouse.php.

Para podermos testar de forma simples vamos adicionar o GraphQL Playground.

sail composer require mll-lab/laravel-graphql-playground

Você poderá acessar o playground pelo endereço http://localhost/graphql-playground.

Para finalizar a configuração do Lighthouse, vamos habilitar o CORS (Cross-Origin Resource Sharing) para seus endpoints GraphQL em config/cors.php alterando a linha:

return [
-      'paths' => ['api/*', 'sanctum/csrf-cookie'],
+      'paths' => ['api/*', 'graphql', 'sanctum/csrf-cookie'],
];

Configurando o Sanctum

O Sanctum já está instalado em nosso projeto, para conferir basta verificar se o arquivo config/sanctum.php existe, então precisamos apenas adicioná-lo ao Lighthouse, editando config/lighthouse.php:

return [
-      'guard' => 'api',
+      'guard' => 'sanctum',
];

Criando a API

Agora que tudo está configurado vamos começar!

Atualizando nosso Schema

A primeira coisa que faremos é adicionar a autenticação da API para permitir que os usuários façam login em suas contas. Normalmente, ao desenvolver uma API REST, você começa definindo o endpoint da API. No GraphQL você tem apenas um endpoint que será usado para executar Queries e Mutations. Cada “endpoint” deve estar presente em nosso esquema GraphQL, então vamos começar criando nossa mutation de login.

Adicione ao arquivo graphql/schema.graphql:

type AccessToken {
  token: String!
}

input LoginInput {
  email: String! @rules(apply: ["email"])
  password: String!
}

extend type Mutation {
  login(input: LoginInput @spread): AccessToken!
    @field(resolver: "App\\GraphQL\\Mutations\\AuthMutation@login")
}

Criando a primeira mutation

Podemos ver que nossa autenticação está utilizando da mutation AuthMutation mas ainda precisamos criá-la com:

sail artisan lighthouse:mutation AuthMutation

Você deve ter um novo arquivo AuthMutation.php em app\GraphQL\Mutations. Essa mutation será responsável por receber o e-mail e senha e lidar com a autenticação.

namespace App\GraphQL\Mutations;

use Illuminate\Auth\AuthManager;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Nuwave\Lighthouse\Exceptions\AuthenticationException;


class AuthMutation
{
    public function __construct(private AuthManager $authManager)
    {
    }

    public function login($_, array $args)
    {
        $userProvider = $this->authManager->createUserProvider('users');

        $user = $userProvider->retrieveByCredentials([
            'email'    => $args['email'],
            'password' => $args['password'],
        ]);

        if (!$user || !$userProvider->validateCredentials($user, $args)) {
            throw new AuthenticationException('The provided credentials are incorrect.');
        }

        if ($user instanceof MustVerifyEmail && !$user->hasVerifiedEmail()) {
            throw new AuthenticationException('Your email address is not verified.');
        }

        return [
            'token' => $user->createToken('login')->plainTextToken,
        ];
    }
}

Para podermos testar nossa autenticação vamos criar um usuário utilizando o Laravel Tinker para facilitar.

sail artisan tinker

Com o Tinker, você pode executar o código PHP diretamente do seu terminal, o que permite executar métodos de classe. Com isso dito, podemos facilmente criar um novo usuário com o UserFactory que vem com a instalação padrão do Laravel:

>>> User::factory()->create(['email' => 'email@provider.com']);

A saída deste comando deve ser uma nova instância do User::class e como chamamos o método create() os dados devem ser persistidos em nosso banco de dados.

[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
=> App\Models\User {#3626
     name: "Peggie Jaskolski PhD",
     email: "email@provider.com",
     email_verified_at: "2022-04-17 21:29:33",
     #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi",
     #remember_token: "HwJWfY62uG",
     updated_at: "2022-04-17 21:29:34",
     created_at: "2022-04-17 21:29:34",
     id: 1,
   }

Autenticando

Já temos nosso usuário criado, e nosso schema e metodos para autenticação prontos, com tudo isso feito, vamos finalmente tentar fazer a requisição acessando nosso playground http://localhost/graphql-playground e executando nossa mutation:

mutation {
  login(input: { email: "email@provider.com", password: "password" }) {
    token
  }
}

E se você seguiu o tutorial corretamente até o momento o retorno será algo como:

{
  "data": {
    "login": {
      "token": "1|4rbAzr3tqnof5Upd12q3RaGLzMbWfIsQVL8wVtAC"
    }
  }
}

Verificando o token

Vamos ao último passo para ter certeza que o token gerado é realmente do usuário solicitado.

Para isso, adicionaremos uma query ao arquivo graphql/schema.graphql:

type Query {
  me: User @auth
}

E simples assim poderemos saber qual usuário está autenticado, ou recebemos um null caso nenhum ou um token inválido seja passado.

No playground basta adicionar nosso token em nosso Authorization Header:

{
  "Authorization": "Bearer 1|4rbAzr3tqnof5Upd12q3RaGLzMbWfIsQVL8wVtAC"
}

Exemplo de autenticação no Playground

Com isso temos nossa primeira API GraphQL feita, então sinta-se à vontade para criar novas mutations e queries.

O Projeto completo pode ser baixado nesse repositório