This short tutorial uses GraphQL, Laravel and SQLite to build a to-do list. It introduces GraphQL, and quickly gets you up and running
Since it was publicly released in 2015 by Facebook, companies like GitHub and Pinterest have started using GraphQL in production. GraphQL introduces lots of improvements over REST. There is this misconception that GraphQL is all about JavaScript. Many different programming languages support GraphQL. So in this tutorial, I will help correct that misconception by showing you how to get started with GraphQL in Laravel.
This tutorial assumes the following:
Also, ensure you have the following installed:
We’ll be using the concept of a to-do list.
We’ll start by creating a new Laravel project. I’ll be using the Laravel installer:
1$ laravel new laravel-graphql-tasks
To use GraphQL is our Laravel application, we’ll be making use of a package called laravel-graphql. Let’s install the package:
1$ cd laravel-graphql-tasks 2 $ composer require folklore/graphql
Note: The rest of the tutorial assumes you already in the
laravel-graphql-tasks
directory
Once that’s done installing, let’s run the command below:
1$ php artisan vendor:publish --provider="Folklore\GraphQL\ServiceProvider"
This will create two new files: config/graphql.php
which is the package configuration file, and resources/views/vendor/graphql/graphiql.php
which will allow us test our application using GraphiQL.
Let’s create a Task model and its corresponding migration file. To do that, run the command below:
1$ php artisan make:model Task -m
Once that’s done, open the migration file that was generated and update the up
method as below:
1// database/migrations/TIMESTAMP_create_tasks_table.php 2 3 public function up() 4 { 5 Schema::create('tasks', function (Blueprint $table) { 6 $table->increments('id'); 7 $table->string('title'); 8 $table->boolean('is_completed')->default(0); 9 $table->timestamps(); 10 }); 11 }
We add basic columns to the tasks
table. We set the is_completed
column to false
by default.
Next, we need to run the migrations. But before we can do that, we need to set up our database. For the purpose of this tutorial, we’ll be using SQLite. So, create a database.sqlite
file inside the database
directory. Lastly, let’s update the .env
file as below:
1// .env 2 3 DB_CONNECTION=sqlite 4 DB_DATABASE=FULL_PATH_TO_DATABASE_SQLITE
Now, let’s run the migration:
1$ php artisan migrate
So as to have some data to work with, let’s create a database seeder to populate the tasks table with some data. Run the command below:
1$ php artisan make:seeder TasksTableSeeder
Then, within the database/factories
directory, create a new TaskFactory.php
file and paste the code below in it:
1// database/factories/TaskFactory.php 2 3 <?php 4 5 use Faker\Generator as Faker; 6 7 $factory->define(App\Task::class, function (Faker $faker) { 8 return [ 9 'title' => $faker->sentence, 10 ]; 11 });
We only specify the value of the title
column since we already defined the is_completed
column to be false
by default.
Next, update the run
method of database/seeds/TasksTableSeeder.php
as below:
1// database/seeds/TasksTableSeeder.php 2 3 public function run() 4 { 5 factory(App\Task::class, 5)->create(); 6 }
Now, we can run the database seeder:
1$ php artisan db:seed --class=TasksTableSeeder
With the setup out of the way, let’s start defining the schemas for our to-do list. Schemas describe how data are shaped and what data on the server can be queried. Schemas can be of two types: Query and Mutation. Our schemas can be define inside config/graphql.php
. We’ll update this file shortly.
Our to-do list will have just one query, which will be to fetch all the tasks that have been added to the GraphQL server. Before we can create a query, we need to first define a type. So, we’ll define a Task
type. To do this, create a new GraphQL
directory within the app
directory. Within the GraphQL
directory, create a new Type
directory. Within app/GraphQL/Type
directory, create a new TaskType.php
file and paste the following code in it:
1// app/GraphQL/Type/TaskType.php 2 3 <?php 4 5 namespace App\GraphQL\Type; 6 7 use GraphQL\Type\Definition\Type; 8 use Folklore\GraphQL\Support\Type as GraphQLType; 9 10 class TaskType extends GraphQLType 11 { 12 protected $attributes = [ 13 'name' => 'Task', 14 'description' => 'A task' 15 ]; 16 17 public function fields() 18 { 19 return [ 20 'id' => [ 21 'type' => Type::nonNull(Type::int()), 22 'description' => 'The id of a task' 23 ], 24 'title' => [ 25 'type' => Type::string(), 26 'description' => 'The title of a task' 27 ], 28 'is_completed' => [ 29 'type' => Type::boolean(), 30 'description' => 'The status of a task' 31 ], 32 ]; 33 } 34 }
We give the type a name and description. Also, we define the fields (id
, title
, is_completed
) that the Task
type will have.
Now, let’s create the query. Create a new Query
directory inside app/GraphQL
, and within the Query
directory, create a new TasksQuery.php
file and paste the following code in it:
1// app/GraphQL/Query/TasksQuery.php 2 3 <?php 4 5 namespace App\GraphQL\Query; 6 7 use GraphQL; 8 use GraphQL\Type\Definition\Type; 9 use Folklore\GraphQL\Support\Query; 10 use App\Task; 11 12 class TasksQuery extends Query 13 { 14 protected $attributes = [ 15 'name' => 'tasks' 16 ]; 17 18 public function type() 19 { 20 return Type::listOf(GraphQL::type('Task')); 21 } 22 23 public function resolve($root, $args) 24 { 25 return Task::all(); 26 } 27 }
We give the query a name of tasks
, then we define the query type (which is the Task
type we defined above). Since we want the query to fetch all the tasks that have been created, we use the listOf
type on the Task
type, which will return an array of tasks. Lastly, we define a resolve
method which will handle the actual fetching of the tasks. We are simply returning all the tasks from the database.
With our type and query defined, let’s add them to config/graphql.php
:
1// config/graphql.php 2 3 'schemas' => [ 4 'default' => [ 5 'query' => [ 6 'tasks' => \App\GraphQL\Query\TasksQuery::class, 7 ], 8 // ... 9 ] 10 ], 11 12 'types' => [ 13 'Task' => \App\GraphQL\Type\TaskType::class, 14 ],
Mutations are used to perform write operations. We’ll create two mutations, which will be used to add a new task and update the status of a task respectively. Create a new Mutation
directory within app/GraphQL
, and within Mutation
, create a new NewTaskMutation.php
file and paste the following code into it:
1// app/GraphQL/Mutation/NewTaskMutation.php 2 3 <?php 4 5 namespace App\GraphQL\Mutation; 6 7 use GraphQL; 8 use GraphQL\Type\Definition\Type; 9 use Folklore\GraphQL\Support\Mutation; 10 use App\Task; 11 12 class NewTaskMutation extends Mutation 13 { 14 protected $attributes = [ 15 'name' => 'newTask' 16 ]; 17 18 public function type() 19 { 20 return GraphQL::type('Task'); 21 } 22 23 public function args() 24 { 25 return [ 26 'title' => [ 27 'name' => 'title', 28 'type' => Type::nonNull(Type::string()) 29 ] 30 ]; 31 } 32 33 public function resolve($root, $args) 34 { 35 $task = new Task(); 36 37 $task->title = $args['title']; 38 $task->save(); 39 40 return Task::find($task->id); 41 } 42 }
We give the mutation a name of newTask
, then we define the type this mutation will return. We define an args
method that returns an array of arguments that the mutation can accept. The mutation will accept just one argument, which is the title of a task. Lastly, we define a resolve
method that does the actual insertion of the new task into the database and returns the newly created task.
What if we want to validate the data before adding a new task? Well, it is possible to add validation rules to a mutation. The laravel-graphql package uses the laravel Validator
to performs validation against the args
. There are two ways to add validation to mutations: we can define a rules
method and return an array containing the rules for each argument, or we define the rules directly while defining an argument. We’ll be opting for the second way.
Update the args
method as below:
1// app/GraphQL/Mutation/NewTaskMutation.php 2 3 public function args() 4 { 5 return [ 6 'title' => [ 7 'name' => 'title', 8 'type' => Type::nonNull(Type::string()), 9 'rules' => ['required'], 10 ] 11 ]; 12 }
We add a rule that makes the title
argument required.
Now, let’s create the mutation to update the status of a task. Create a new UpdateTaskStatusMutation.php
file within app/GraphQL/Mutation
and paste the following code into it:
1// app/GraphQL/Mutation/UpdateTaskStatusMutation.php 2 3 <?php 4 5 namespace App\GraphQL\Mutation; 6 7 use GraphQL; 8 use GraphQL\Type\Definition\Type; 9 use Folklore\GraphQL\Support\Mutation; 10 use App\Task; 11 12 class UpdateTaskStatusMutation extends Mutation 13 { 14 protected $attributes = [ 15 'name' => 'updateTaskStatus' 16 ]; 17 18 public function type() 19 { 20 return GraphQL::type('Task'); 21 } 22 23 public function args() 24 { 25 return [ 26 'id' => [ 27 'name' => 'id', 28 'type' => Type::nonNull(Type::int()), 29 'rules' => ['required'], 30 ], 31 'status' => [ 32 'name' => 'status', 33 'type' => Type::nonNull(Type::boolean()), 34 'rules' => ['required'], 35 ] 36 ]; 37 } 38 39 public function resolve($root, $args) 40 { 41 $task = Task::find($args['id']); 42 43 if (!$task) { 44 return null; 45 } 46 47 $task->is_completed = $args['status']; 48 $task->save(); 49 50 return $task; 51 } 52 }
This is quite similar to the NewTaskMutation
. It accepts two arguments: the ID of the task to update and the status of the task. The resolve
method gets the task with the supplied ID from the database. If there is no task with the supplied ID, we simply return null
. Otherwise, we update the task with the supplied status and persist to the database. Finally, we return the update the task.
To wrap up the mutations, let’s add them to config/graphql.php
:
1// config/graphql.php 2 3 'schemas' => [ 4 'default' => [ 5 // ... 6 'mutation' => [ 7 'newTask' => \App\GraphQL\Mutation\NewTaskMutation::class, 8 'updateTaskStatus' => \App\GraphQL\Mutation\UpdateTaskStatusMutation::class, 9 ] 10 ] 11 ],
So far, we have created a GraphQL server with one query and two mutations. Let’s now see how we test out the server using GraphiQL. Recall that when we published the laravel-graphql package files, a resources/views/vendor/graphql/graphiql.php
was also created. This will allow us to test our GraphQL server within our Laravel app.
Get the app running with the command below:
1$ php artisan serve
This will get the app running on http://127.0.0.1:8000
, then visit http://127.0.0.1:8000/graphiql in your browser. GraphiQL should now be running as in the image below:
We can see our GraphQL server in action:
In this tutorial, we have seen how to use GraphQL in a Laravel application. We’ve only scratched the surface of working with GraphQL in Laravel applications. In my next tutorial, we’ll dive deeper as we’ll be building an API with GraphQL and Laravel. So stay tuned.
The complete code for this tutorial is available on GitHub.