Creating GraphQL APIs with Laravel
Tags: php, laravel
Published: 2024-02-15 17:25:25

*This article was originally written by [Samson Omojola](https://www.honeybadger.io/blog/authors/omojolasamsonade/) on the [Honeybadger Developer Blog](https://www.honeybadger.io/blog/graphql-laravel/).*

Application Programming Interfaces (APIs) are a crucial element of modern web development. They allow different applications and services to communicate with each other, sharing data and functionality, which enables developers to create complex, interconnected systems that would be impossible with standalone applications.

One of the most popular and powerful API technologies today is GraphQL. Unlike traditional REST APIs, which have fixed endpoints and return predefined data structures, GraphQL APIs allow clients to precisely define the data they need and receive it in a predictable and hierarchical format. This allows for more flexible and efficient data fetching and eliminates the need for over-fetching or under-fetching data.

In this tutorial, we will learn how to create a GraphQL API with [Laravel](https://laravel.com/), a popular PHP web framework. We will be creating a simple student model, seeding the database with dummy data, setting up a database connection, and creating a GraphQL server by defining our API's schema, queries, and mutations. We’ll also learn how to make requests to our API (test our endpoints) using a tool like Insomnia or Postman. By the end of this tutorial, you will have a working GraphQL API that you can continue to expand and improve.

[Here's a link to the GitHub repo for this article.](https://github.com/omojolasamson/GraphQL-Laravel)

**There are several advantages to using GraphQL for your API:**

- **Flexibility**: As mentioned above, with GraphQL, clients can specify the data they need and receive it in a predictable and hierarchical format. This allows for more flexible and efficient data fetching and eliminates the tendency of over-fetching or under-fetching data.
- **Better performance**: Because GraphQL APIs allow clients to specify precisely the data they need, clients can often fetch it in a single request, reducing the number of roundtrips to the server and improving performance.
- **Strongly typed schema**: GraphQL schemas are strongly typed, which means that the data returned by a GraphQL API are always in the same format. This makes it easier to predict the shape of the data and reduces the need for clients to handle edge cases and unexpected data structures.
- **Ease of use**: GraphQL is a simple and intuitive query language that’s easy for developers to learn and use. It also has a large and active developer community, with many libraries and tools (e.g., Apollo, Relay, Prisma, and GraphiQL) available to help with common tasks.
- **Backward compatibility**: Because GraphQL allows clients to specify the data they need, it is possible to make backwards-compatible changes to the API without breaking existing clients.

## Prerequisites

To create a GraphQL API with Laravel, you will need to have a basic understanding of the Laravel framework and the GraphQL query language.

Additionally, make sure to have the following installed on your machine:

- PHP 7.4 or higher
- [Composer](https://getcomposer.org/)
- MySQL
- Laravel 7.0 or higher

## Step 1: Setting up the Laravel project

Open your terminal and navigate to the directory where you want to create your project. Then, run the following command to create a new Laravel project:

```bash
composer create-project --prefer-dist laravel/laravel graphql-tutorial
```

This will create a new Laravel project in a directory called `graphql-tutorial`.

## Step 2: Setting up the database

Next, we need to set up a database connection. Open the `.env` file in the root of your project and update the following lines with your database credentials:

```php

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=YOUR_DATABASE_NAME
DB_USERNAME=YOUR_DATABASE_USERNAME
DB_PASSWORD=YOUR_DATABASE_PASSWORD
```

## Step 3: Creating the student model

Next, we will create a student model and a corresponding migration file to create a `students` table in the database. Run the following command to create the model and the migration file:

```bash
php artisan make:model Student -m
```

This will create a `Student` model and a migration file in the `database/migrations` directory. Open the migration file and add the following columns to the `students` table:

```php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateStudentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('students', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email');
            $table->integer('age');
            $table->string('country');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('students');
    }
}
```

Next, run the following command to create the `students` table in the database:

```bash
php artisan migrate
```

You’ll also want to add these fields to the Student model in `app/Student.php`:

```php

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Student extends Model
{
    protected $fillable = ["name", "email", "age", "country"];
}
```

## Step 4: Creating a seeder file

Next, we will create a seeder file to seed the `students` table with dummy data:

```bash
php artisan make:seeder StudentTableSeeder
```

This will create a seeder file called `StudentTableSeeder.php` in the `database/seeds` directory.

Open the seeder file and add the following code:

```php

<?php

use Illuminate\Database\Seeder;
use App\Student;

class StudentTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // Create 10 students
        factory(Student::class, 10)->create();
    }
}
```

This code uses the Laravel factory to create 10 students and insert them into the `students` table. Next, open the `DatabaseSeeder.php` file and add the following line to the `run()` method:

```php
$this->call(StudentTableSeeder::class);
```

This will run the `StudentTableSeeder` when you run the `db:seed` command. Finally, run the following command to seed the `students` table with dummy data:

```bash
php artisan db:seed
```

## Step 5: Installing the rebing/graphql-laravel package

Next, we will install the `rebing/graphql-laravel` package, which will allow us to easily create a GraphQL server in Laravel.

```bash
composer require rebing/graphql-laravel
```

This will add the necessary dependencies to your Laravel project. Once the package is installed, run the following command to publish the GraphQL configuration file:

```bash
php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider"
```

## Step 6: Creating the GraphQL server

Next, we will create the GraphQL server. First, create a `graphql` directory in the `routes` directory. Then, create a file called `StudentType.php` in the `routes/graphql` directory and add the following code:

```php
<?php

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Type as GraphQLType;

class StudentType extends GraphQLType
{
    protected $attributes = [
        'name' => 'Student',
        'description' => 'A student',
        'model' => \App\Student::class
    ];

    public function fields(): array
    {
        return [
            'id' => [
                'type' => Type::nonNull(Type::int()),
                'description' => 'The id of the student'
            ],
            'name' => [
                'type' => Type::string(),
                'description' => 'The name of the student'
            ],
            'email' => [
                'type' => Type::string(),
                'description' => 'The email of the student'
            ],
            'age' => [
                'type' => Type::int(),
                'description' => 'The age of the student'
            ],
            'country' => [
                'type' => Type::string(),
                'description' => 'The country of the student'
            ],
            'created_at' => [
                'type' => Type::string(),
                'description' => 'The date the student was created',
                'resolve' => function($model) {
                    return $model->created_at;
                }
            ],
            'updated_at' => [
                'type' => Type::string(),
                'description' => 'The date the student was last updated',
                'resolve' => function($model) {
                    return $model->updated_at;
                }
            ]
        ];
    }
}
```

The code above creates a GraphQL type called `StudentType` that represents a student in the database. It defines fields for the `id`, `name`, `email`, `age`, `country`, `created_at`, and `updated_at` columns of the `students` table.

In the `fields()` function, you’ll notice each field in the `StudentType` has `type` and `description` parameters. Fields in a GraphQL type require a `type` and `description` because these parameters provide important information for the GraphQL server to understand and validate the data being requested or provided by the client. The `type` specifies the data type of the field, such as a string or integer, and the `description` provides additional information about the field, such as its purpose or expected format. This information is used by the GraphQL server to properly handle and respond to client queries and mutations, as well as by various tools, such as GraphQL clients and IDEs, to generate better documentation and support for developers.

Now, create a file called `StudentsQuery.php` in the `routes/graphql` directory. Open the file and add the following code:

```php

<?php

use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Facades\GraphQL;
use Rebing\GraphQL\Support\Query;

class StudentsQuery extends Query
{
    protected $attributes = [
        'name' => 'students'
    ];

    public function type(): Type
    {
        return Type::listOf(GraphQL::type('student'));
    }

    public function args(): array
    {
        return [
            'id' => [
                'name' => 'id',
                'type' => Type::int()
            ],
            'name' => [
                'name' => 'name',
                'type' => Type::string()
            ],
            'email' => [
                'name' => 'email',
                'type' => Type::string()
            ],
            'age' => [
                'name' => 'age',
                'type' => Type::int()
            ],
            'country' => [
                'name' => 'country',
                'type' => Type::string()
            ]
        ];
    }

    public function resolve($root, $args)
    {
        if (isset($args['id'])) {
            return Student::where('id', $args['id'])->get();
        }

        if (isset($args['name'])) {
            return Student::where('name', $args['name'])->get();
        }

        if (isset($args['email'])) {
            return Student::where('email', $args['email'])->get();
        }
    
        if (isset($args['age'])) {
            return Student::where('age', $args['age'])->get();
        }
    
        if (isset($args['country'])) {
            return Student::where('country', $args['country'])->get();
        }
    
        return Student::all();
    }
}
```

The code we have above defines a GraphQL query field for a list of students. The `protected $attributes` array sets the field name as "students". Thus, when a client application makes a query, it will use this name to request the list of students. The public function `type()` returns the type of field. In this case, it is using the helper function `Type::listOf()` to indicate that the field is a list of items. The argument passed to the function, `GraphQL::type('student')`, specifies that each item in the list is of the `Student` type. Therefore, when the client makes a query for this field, the server will know that it is expecting a list of student objects and will retrieve and return the appropriate data to the client.

The public function `args()` returns an array of input fields for the query. We’ll use these fields to retrieve data from our GraphQL server. The `name` parameter for each field specifies how data from this field will be retrieved on the client side, and the `type` parameter specifies the type of data that will be retrieved from this field.

The `resolve` function in a GraphQL query is responsible for fetching data from the server based on the input arguments. The function takes in two parameters, `$root` and `$args`. `$root` refers to the root object of the query, and `$args` refers to the input arguments passed to the query.

In the function, we start by checking whether the `id` argument is passed in the query. If it is, we search for the id in our database using Eloquent's `where` method, get the result using the `get` method, and return it to our client. When the `name` argument is passed, we return all the students with the given name by using Eloquent's `where` method and getting the result by using the `get` method. The same logic applies to the `email`, `age`, and `country` arguments. If none of these arguments are passed, it returns all the students by using the `all` method.

### Mutation

You should know this already, but a GraphQL mutation is a type of operation that allows a client to modify data on the server. It is similar to a POST, PUT, or PATCH request in REST. Here are the mutations that our server needs:

- Create: Allows the client to create a new student on the server.
- Update: Allows the client to update an existing student on the server.
- Delete: Allows the client to delete a student on the server.

For our first mutation, create a file called CreateStudentMutation.php in the `routes` directory and add the following code:

```php

<?php

use App\Student;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class CreateStudentMutation extends Mutation
{
protected $attributes = [
'name' => 'createStudent'
];

public function type(): Type
{
    return GraphQL::type('student');
}

public function args(): array
{
    return [
        "id" => [
            'name' => 'id',
            'type' => Type::nonNull(Type::int()),
        ],
        'name' => [
            'name' => 'name',
            'type' => Type::nonNull(Type::string())
        ],
        'email' => [
            'name' => 'email',
            'type' => Type::nonNull(Type::string())
        ],
        'age' => [
            'name' => 'age',
            'type' => Type::nonNull(Type::int())
        ],
        'country' => [
            'name' => 'country',
            'type' => Type::nonNull(Type::string())
        ]
    ];
}

public function resolve($root, $args)
{
    $student = new Student();
    $student->name = $args['name'];
    $student->email = $args['email'];
    $student->age = $args['age'];
    $student->country = $args['country'];
    $student->save();

    return $student;
}
}
```

Above, we created a GraphQL mutation called `createStudent` that allows clients to create a new student in our database. It takes the `name`, `email`, `age`, and `country` of the student as arguments.

The `protected $attributes` array specifies how a client utilizes the mutation. The public function `type()` returns the type of mutation, the `student` object.

The `args()` function returns an array of arguments. These fields will be created for each mutation entry. Each entry has a `name` (the name of the database column) and a (data) `type` like `int` and `String`. The `Type::nonNull` constraint ensures that null values are not entered into the database.

The `resolve` function does the final work of entering the values provided into the database. In this function, we create an instance of the `Student` model, save the values for `name`, `email`, `age`, and `country` in some variables, and save the values to our database with `$student->save()`.

Next, to update student entries in our database, create a file called **UpdateStudentMutation.php** in the `routes` directory and add the following code:

```php

<?php
namespace App\graphql\Mutations;
use App\Student;
use Rebing\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class UpdateStudentMutation extends Mutation
{
    protected $attributes = [
        "name" => "updateStudent",
    ];
    public function type(): Type
    {
        return GraphQL::type("Student");
    }
    public function args(): array
    {
        return [
        'name' => [
            'name' => 'name',
            'type' => Type::nonNull(Type::string())
        ],
        'email' => [
            'name' => 'email',
            'type' => Type::nonNull(Type::string())
        ],
        'age' => [
            'name' => 'age',
            'type' => Type::nonNull(Type::int())
        ],
        'country' => [
            'name' => 'country',
            'type' => Type::nonNull(Type::string())
        ]
    ];
    }
    public function resolve($root, $args)
    {
        $student = Student::findOrFail($args["id"]);
        $student->fill($args);
        $student->save();
        return $student;
    }
}
```

The code for **CreateStudentMutation** is very similar to the code for **UpdateStudentMutation**. The only difference is in the `resolve` function, where we search for the specific student to update. With `Student::findOrFail($args["id"])`, we take the student `id` supplied by a client application and search for it in the database. With the `fill` function, we replace all of the data in the row of the id supplied with the new data provided. Then, we save the new data in the database.

To delete a student from the database, create a file called **DeleteStudentMutation.php** in the `routes` directory and add the following code:

```php

<?php
namespace App\graphql\Mutations;
use App\Student;
use GraphQL\Type\Definition\Type;
use Rebing\GraphQL\Support\Mutation;
class DeleteStudentMutation extends Mutation
{
    protected $attributes = [
        "name" => "deleteStudent",
        "description" => "Delete a student",
    ];
    public function type(): Type
    {
        return Type::boolean();
    }
    public function args(): array
    {
        return [
            "id" => [
                "name" => "id",
                "type" => Type::int(),
                "rules" => ["required"],
            ],
        ];
    }
    public function resolve($root, $args)
    {
        $student = Student::findOrFail($args["id"]);
        return $student->delete() ? true : false;
    }
}
```

To delete a student from our database, all we need is an id, which we get from a client application. `"rules" => ["required"]` ensures that an id is provided. With `findOrFail`, we search for the id in our database, and the `delete()` function deletes all of the data with that id.

## Registering our query, mutations, and type

The last step is to register the type, query, and mutations that we just created in the GraphQL configuration file, `config/graphql.php`.

```php

return [
...
'schemas' => [
        'default' => [
                'query' => [
                        'students' => App\GraphQL\Queries\StudentsQuery::class,
                ],
                'mutation' => [
                        // Create a student
                        'createStudent' => App\GraphQL\Mutations\CreateStudentMutation::class,
                        // update student
                        'updateStudent' => App\GraphQL\Mutations\UpdateStudentMutation::class,
                        // delete a student
                        'deleteStudent' => App\GraphQL\Mutations\DeleteStudentMutation::class,
                ],
                'middleware' => [],
                'method' => ['get', 'post'],
        ],
],
'types' => [
        'Student' => App\GraphQL\Types\StudentType::class,
],
...
]
```

## Step 7: Testing the endpoints

Now that the GraphQL server is set up, we can test the endpoints. Open your browser and navigate to `http://localhost:8000/graphql`. You should see the GraphQL Playground interface. In the left-hand panel, type the following query to fetch all students:

```graphql

{
  students {
    id
    name
    email
    age
    country
  }
}
```

![Query Students](https://www.honeybadger.io/images/blog/posts/graphql-laravel/query.png)
_Query Students_

Then, click the "Play" button to execute the query. You should see a list of students in the right-hand panel.

To test creating a student with a mutation, you can use the following mutation:

```graphql

mutation {
  createStudent(name: "New Student", email: "newstudent@example.com", age: 20, country: "Canada") {
    id
    name
    email
    age
    country
  }
}
```

![Create a Student](https://www.honeybadger.io/images/blog/posts/graphql-laravel/create.png)
_Create a Student_

To test updating a student with a mutation, you can use the following mutation:

```graphql

mutation {
  updateStudent(id: 1, name: "Updated Student", email: "updatedstudent@example.com", age: 21, country: "USA") {
    id
    name
    email
    age
    country
  }
}
```

![Update a Student](https://www.honeybadger.io/images/blog/posts/graphql-laravel/update.png)
_Update a Student_

You can execute these mutations in the same way as the queries, by typing the mutation in the left-hand panel and clicking the "Play" button.

To delete a student from our database, we use the following mutation:

```graphql

mutation {
  deleteStudent(id : 1)
}
```

![Delete a Student](/images/blog/posts/graphql-laravel/delete.png)
_Delete a Student_

## Conclusion

In this article, we’ve learned how to create a GraphQL API using Laravel and the rebing/graphql-laravel package. We’ve also created a Student model, seeded the database with dummy data, set up a database connection, created the GraphQL server, and tested the endpoints. Now, you can create your own GraphQL APIs with Laravel and the graphql-laravel package.

I hope you found this tutorial helpful. Thank you for following along!