# GraphQL en PHP

## Introducción

[Laravel](https://laravel.com/) es un framework de desarrollo web de código abierto, escrito en PHP, que sigue el patrón de arquitectura MVC (Modelo-Vista-Controlador); ofrece una amplia gama de características y funcionalidades que agilizan el proceso de desarrollo, como enrutamiento flexible, gestión de sesiones, generación de consultas SQL, migraciones de base de datos, autenticación de usuarios, caché, entre otras.

[Lighthouse](https://lighthouse-php.com/) es una biblioteca de código abierto para Laravel que permite construir servidores GraphQL de manera sencilla y eficiente. Simplifica la implementación de GraphQL en Laravel al proporcionar características como la generación automática de esquemas GraphQL a partir de los modelos de Eloquent (el ORM de Laravel), resolvers predeterminados para resolver consultas y mutaciones básicas, gestión de autorización y autenticación, paginación, validación de entradas GraphQL, entre otros.

En este tutorial, aprenderemos cómo crear una API integrando Laravel y Lighthouse.

## Proyecto

Consiste en crear una API utilizando el framework Laravel y la biblioteca Lighthouse para implementar un servidor GraphQL. La API permitirá gestionar los datos de dos modelos: "Director" y "Movie". Estableceremos una relación entre ellos, donde un director puede tener varias películas y cada película pertenece a un director.

La API nos permitirá gestionar las operaciones CRUD (Create, Read, Update, Delete) para realizar acciones como crear, leer, actualizar y eliminar directores y películas.

## Instalación y configuración

Comencemos creando un nuevo proyecto Laravel con el siguiente comando.

```plaintext
composer create-project --prefer-dist laravel/laravel laravel-lighthouse
```

Yo llamé al proyecto "laravel-lighthouse"; entra a la carpeta generada y continuamos con la instalación de la biblioteca de "Lighthouse".

```plaintext
composer require nuwave/lighthouse
```

Una vez finalizada la instalación, ejecuta el siguiente comando para publicar los archivos de configuración de Lighthouse.

```plaintext
php artisan vendor:publish --tag=lighthouse-schema
```

Esto creará un fichero `graphql/schema.graphql` , en donde definiremos nuestros tipos de datos.

Continuamos con la instalación de [GraphiQL](https://github.com/mll-lab/laravel-graphiql), una herramienta de desarrollo para probar nuestra API.

```plaintext
composer require mll-lab/laravel-graphiql
```

Finalizamos habilitando CORS para el endpoint de nuestra API en `config/cors.php`

```php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

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

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];
```

Continuamos con la configuración de nuestra base de datos.

## Base de datos

Abre tu gestor de base de datos y crea uno para nuestro proyecto.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686522921204/16d914d7-7bfa-4069-a183-e4152ef652cd.png align="center")

Yo lo llamé "laravel\_lighthouse". Ahora abrimos el fichero `.env` para indicarle a Laravel que base de datos debe usar.

```apache
DB_DATABASE=laravel_lighthouse
```

Terminamos con la configuración, seguimos con la definición de las migraciones para nuestras tablas.

## Migraciones

Comenzamos con la migración de la tabla `directors` . Ejecuta el siguiente comando.

```plaintext
php artisan make:migration create_directors_table --create=directors
```

Esto creará un fichero `database/migrations/create_directors_table.php` , lo abrimos y definimos los campos.

```php
public function up(): void
    {
        Schema::create('directors', function (Blueprint $table) {
            $table->id();

            $table->string("name");
            $table->string("lastname");

            $table->timestamps();
        });
    }
```

Continuamos con la migración de la tabla `movies` . Ejecuta el comando.

```plaintext
php artisan make:migration create_movies_table --create=movies
```

Abre el fichero `database/migrations/create_movies_tabla.php` para definir los campos.

```php
public function up(): void
    {
        Schema::create('movies', function (Blueprint $table) {
            $table->id();

            $table->string("title");
            $table->string("genre");

            $table->unsignedBigInteger("director_id");
            $table->foreign("director_id")->references("id")->on("directors")->onDelete("cascade");
            
            $table->timestamps();
        });
    }
```

Las líneas `$table->unsignedBigInteger("director_id")` y `$table->foreign("director_id")->refereces("id")->on("directors")->onDelete("cascade")` son importantes para crear la relación "uno a muchos" entre las dos tablas. La función `onDelete("cascade")` determina que si un registro en la tabla padre (directors) es borrado, los registros relacionados en la tabla hija (movies) también se borrarán. Es importante para que Laravel no dispare un error de integridad de base de datos.

Ejecutamos las migraciones con el siguiente comando.

```plaintext
php artisan migrate
```

Abre tu gestor de base de datos, deberías ver las tablas y la relación establecida.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686524115803/6b76cc73-49ad-42e2-b34e-2d839cf1731e.png align="center")

A continuación los modelos Director y Movie.

## Modelos

Para crear los modelos Director y Movie ejecuta los siguientes comandos.

```plaintext
php artisan make:model Director
```

```plaintext
php artisan make:model Movie
```

Se crearán los ficheros `app/Models/Director.php` y `app/Models/Movie.php` . Comenzamos con el modelo Director.

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Director extends Model
{
    use HasFactory;

    protected $fillable = [
        "name",
        "lastname",
    ];

    public function movies() {
        return $this->hasMany(Movie::class);
    }
}
```

Primero indicamos los campos `name` y `lastname` como "mass assignable", luego la función `public function movies()` establece que este modelo puede tener muchas películas a través de `$this->hasMany(Movie::class)` .

Ahora continuamos con el modelo Movie.

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Movie extends Model
{
    use HasFactory;

    protected $fillable = [
        "title",
        "genre",
        "director_id",
    ];

    public function director() {
        return $this->belongsTo(Director::class);
    }
}
```

Indicamos los campos "mass assignable" para `title`, `genre` y `director_id`. La función `public function director()` determina que este modelo pertenece a un director a través de `$this->belongsTo(Director::class)`.

A continuación definimos los tipos de datos en el fichero de esquemas de graphql.

## GraphQL

Para definir los tipos de datos, abre el fichero `graphql/schema.graphql` .

```graphql
type Director {
  id: ID!
  name: String!
  lastname: String!
  created_at: DateTime!
  updated_at: DateTime!

  movies: [Movie!]! @hasMany
}

type Movie {
  id: ID!
  title: String!
  genre: String!
  created_at: DateTime!
  updated_at: DateTime!

  director: Director! @belongsTo
}
```

Lo que podemos destacar aquí son las directivas `@hasMany` y `@belognsTo`. Esto es una característica específica de Lighthouse y proporcionan una forma fácil y declarativa de agregar características avanzadas a tu API GraphQL.

Es este caso se define la relación "uno a muchos" entre los tipos de datos.

Ahora definimos las queries.

```graphql
type Query {

  directors: [Director!] @all

  director(id: ID! @whereKey): Director @find

  movies: [Movie!] @all

  movie(id: ID! @whereKey): Movie @find

}
```

La integración de Lighthouse en Laravel permite generar automáticamente los resolvers correspondientes para manejar estas consultas.

1. `directors: [Director!] @all`: Esta query devuelve una lista de todos los directores disponibles en la base de datos. La directiva `@all` indica que queremos obtener todos los registros de la tabla de directores.
    
2. `director(id: ID! @whereKey): Director @find`: Esta query permite buscar un director específico por su `id`. La directiva `@whereKey` indica que el valor proporcionado para `id` se utilizará como clave de búsqueda en la base de datos.
    
3. `movies: [Movie!] @all`: Esta query devuelve una lista de todas las películas disponibles en la base de datos. Al igual que la query `directors`, la directiva `@all` se utiliza para obtener todos los registros de la tabla de películas.
    
4. `movie(id: ID! @whereKey): Movie @find`: Esta query permite buscar una película específica por su `id`. Al igual que la query `director` la directiva `@whereKey` indica que el valor proporcionado para `id` se utilizará como clave de búsqueda en la base de datos.
    

Ahora definimos las mutaciones.

```graphql
type Mutation {

  createDirector(name: String!, lastname: String!): Director @create

  updateDirector(id: ID!, name: String!, lastname: String!): Director @update

  deleteDirector(id: ID! @whereKey): Director @delete

  createMovie(title: String!, genre: String!, director_id: ID!): Movie @create

  updateMovie(id: ID!, title: String!, genre: String!, director_id: ID!): Movie @update

  deleteMovie(id: ID! @whereKey): Movie @delete

}
```

Estas mutations utilizan las directivas `@create`, `@update` y `@delete` de Lighthouse para especificar las operaciones a realizar en la base de datos.

1. `createDirector(name: String!, lastname: String!): Director @create`: Esta mutation permite crear un nuevo director. Toma dos argumentos: `name` y `lastname`, que son de tipo `String!` y se requieren para crear el director. La directiva `@create` indica que queremos realizar una operación de creación en la base de datos. La mutation devuelve un objeto de tipo `Director`.
    
2. `updateDirector(id: ID!, name: String!, lastname: String!): Director @update`: Esta mutation permite actualizar un director existente. Toma tres argumentos: `id`, `name` y `lastname`. El argumento `id` es de tipo `ID!` y se requiere para identificar el director que se actualizará. Los argumentos `name` y `lastname` son de tipo `String!` y se utilizan para actualizar los campos correspondientes del director. La directiva `@update` indica que queremos realizar una operación de actualización en la base de datos. La mutation devuelve un objeto de tipo `Director`.
    
3. `deleteDirector(id: ID! @whereKey): Director @delete`: Esta mutation permite eliminar un director existente. Toma un argumento `id` de tipo `ID!`, que se requiere para identificar el director que se eliminará. La directiva `@whereKey` indica que el valor proporcionado para `id` se utilizará como clave de búsqueda en la base de datos. La directiva `@delete` indica que queremos realizar una operación de eliminación en la base de datos. La mutation devuelve un objeto de tipo `Director`.
    

Con estas mutaciones tenemos todas las operaciones CRUD para el modelo Director.

Las mutaciones para el modelo Movie son:

1. `createMovie(title: String!, genre: String!, director_id: ID!): Movie @create`: Esta mutation permite crear una nueva película. Toma tres argumentos: `title`, `genre` y `director_id`. Los argumentos `title` y `genre` son de tipo `String!` y se requieren para crear la película. El argumento `director_id` es de tipo `ID!` y se utiliza para establecer la relación entre la película y el director correspondiente. La directiva `@create` indica que queremos realizar una operación de creación en la base de datos. La mutation devuelve un objeto de tipo `Movie`.
    
2. `updateMovie(id: ID!, title: String!, genre: String!, director_id: ID!): Movie @update`: Esta mutation permite actualizar una película existente. Toma cuatro argumentos: `id`, `title`, `genre` y `director_id`. El argumento `id` es de tipo `ID!` y se requiere para identificar la película que se actualizará. Los argumentos `title`, `genre` y `director_id` son de tipo `String!` y `ID!`, respectivamente, y se utilizan para actualizar los campos correspondientes de la película. La directiva `@update` indica que queremos realizar una operación de actualización en la base de datos. La mutation devuelve un objeto de tipo `Movie`.
    
3. `deleteMovie(id: ID! @whereKey): Movie @delete`: Esta mutation permite eliminar una película existente. Toma un argumento `id` de tipo `ID!`, que se requiere para identificar la película que se eliminará. La directiva `@whereKey` indica que el valor proporcionado para `id` se utilizará como clave de búsqueda en la base de datos. La directiva `@delete` indica que queremos realizar una operación de eliminación en la base de datos. La mutation devuelve un objeto de tipo `Movie`.
    

Hemos finalizado con todas las operaciones CRUD de nuestra API. Pasaremos a probarlos con GraphiQL.

## Probando la API

Iniciamos el servidor de desarrollo con el comando.

```plaintext
php artisan serve
```

Abrimos la herramienta de desarrollo de GraphiQL en `localhost:8000/graphiql` .

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686534571187/c58c37f4-371b-4536-b1ca-69f10ab8741e.png align="center")

Haciendo clic en la esquina superior izquierda puedes consultar los tipos definidos para nuestra API.

Comenzamos provando las mutaciones para añadir algunos directores y películas.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686534710317/d56f6d3c-bab3-41c3-bcb4-c4530a27dae5.png align="center")

Añadí tres directores: Denis Villeneuve, Alejandro González Iñarritu y Alfonso Cuarón.

Podemos verificarlo en la base de datos.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686536358602/e5b47516-067c-405a-b525-242de1db72b8.png align="center")

Ahora agreguemos las películas.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686535698248/b8303495-6cc8-4a0f-8c81-2abda71f858b.png align="center")

Ten el cuenta como el campo `director_id` vincula la película con su correspondiente director.

Añadí cuatro, de Villenevue, Dune y Blade Runner 2049, de Iñarritu Revenant, y de Cuarón Gravedad.

Lo vemos en la base de datos.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686536395656/01eb9c46-c9fa-4468-a0eb-d5ef953b8ae0.png align="center")

Ahora que tenemos datos en nuestras tablas, probemos algunas queries.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686535770552/c534dc40-0b18-40b7-8bf7-2aa2678629de.png align="center")

Consultamos todos los directores y además pedimos las películas que tienen. Podemos ver que la relación funciona correctamente.

Ahora consultamos las películas.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686536229669/5e7d6008-aa9e-4c7f-8b71-3294868e8536.png align="center")

Consultamos el nombre de la película y el nombre y apellido del director. Todo funciona correctamente.

Probamos las consultas por ID.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686536993518/45042efc-2c41-44c0-93e1-267a3004a773.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1686537023749/3ec9fcb8-bb7e-4126-be7b-97f0da17b71e.png align="center")

Puedes seguir prabando las demás consultas y mutaciones. Por ahora finalizamos con el tutorial.

## Conclusión

Hemos explorado cómo crear una API utilizando Laravel y Lighthouse para implementar un servidor GraphQL. Hemos creado dos modelos, "Director" y "Movie", y hemos establecido una relación entre ellos: un director puede tener varias películas y cada película pertenece a un director.

Hemos explorado cómo Laravel y Lighthouse trabajan en conjunto para simplificar y agilizar el desarrollo de APIs GraphQL. Hemos aprovechado las funcionalidades de Laravel, como las migraciones, los modelos de Eloquent y las operaciones de consulta, y hemos utilizado Lighthouse para generar automáticamente los resolvers y agregar características avanzadas a nuestra API.

Puedes encontrar el proyecto completo en mi repositorio de GitHub haciendo clic [**AQUÍ**](https://github.com/AlegreCode/laravel-lighthouse).

Espero que lo hayas encontrado entretenido, instructivo y claro. Si tienes alguna duda, puedes hacérmelo saber en los comentarios. Pronto estaré subiendo más tutoriales.

Nos vemos en la próxima. Saludos!👋😊
