Lighthouse:Building a GraphQL Server with Laravel

GraphQL is a query language used to interact with your API which provides some benefits compared to alternative architectures such as REST. GraphQL is extremely handy when used to serve as an endpoint for mobile and single-page applications. GraphQL allows you to query nested and related data in a request with relative ease, allowing developers to obtain the exact data they need in a single round trip to the server.

In this article, we will cover how to use Lighthouse package to build a GraphQl server with Laravel. This package makes it so simple and easy to create  a GraphQL api in Laravel. We will assume that you already are familiar with the basics of GraphQL and Laravel.

Overview

 we will create a GraphQL API for a simple Blog from scratch with:

  • Laravel 5.7
  • Lighthouse 2.x
  • Laravel GraphQL Playground
  • MySQL

Install

Let’s start by creating a new Laravel via Composer project:

composer create-project --prefer-dist laravel/laravel laravel-graphql

add the lighthouse package by running the following:

composer require nuwave/lighthouse

we will use Laravel GraphQL Playground as an IDE for GraphQL queries. It's like Postman for GraphQL

composer require mll-lab/laravel-graphql-playground

Then publish the configurations files and the default schema:

# lighthouse
php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider"

# playground
php artisan vendor:publish --provider="MLL\GraphQLPlayground\GraphQLPlaygroundServiceProvider"

 

The default schema will be published to graphql/schema.graphql.

 

Database

Run database migrations to create the users table:

php artisan migrate

Seed the database with some fake users:

php artisan tinker
factory('App\User', 10)->create();

Models and Migrations

One user can publish many posts, and each post has many comments from anonymous users.

let’s go ahead and create our post model and a migration file to create the associated table:

php artisan make:model -m Post
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}
<?php

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

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->string('title');
            $table->string('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

and create the comment model and a migration file to create the associated table:

php artisan make:model -m Comment

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    public function post()
    {
        return $this->belongsTo(Post::class);
    }
}

<?php

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

class CreateCommentsTable extends Migration
{
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('post_id');
            $table->string('reply');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('comments');
    }
}

run the migrations:

php artisan migrate

add the posts relation to app/User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

Creating the schema

the following file routes/graphql/schema.graphql is the one containing our whole schema for the graphql server.

First, we define the root Query type which contains two different queries for retrieving posts:

type Query{
    posts: [Post!]! @all
    post(id: Int! @eq): Post @find
}
  • @all just gets you a list of all Post models
  • @find and @eq are combined to retrieve a single Post by its ID

Let’s take a moment to break down our query type.Our first field is the posts field which returns an array of Post object types. The @alldirective tells Lighthouse to run an Eloquent query, using our Post model and get all of the results. This would be the same as running the following:

$posts = \App\Post::all();

Our second defined field on our query type is the call post, which takes an id as an argument and returns a single Post object type. We’ve also added two directives to help Lighthouse automatically build a query for us and return a single Post model. The @eq directive tells Lighthouse to add a where on our id column, and the @find directive instructs Lighthouse to return a single result. To write this query using Laravel’s query builder, it would look like this:

$post = \App\Post::where('id', $args['id'])->first();

Then, we add additional type definitions that clearly define the shape of our data.

type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]! @hasMany
}

type Post {
    id: ID!
    title: String!
    content: String!
    user: User! @belongsTo
    comments: [Comment!]! @hasMany
}

type Comment{
    id: ID!
    reply: String!
    post: Post! @belongsTo
}

Just like in Eloquent, we express the relationship between our types using the @belongsTo and @hasMany directives.

Querying Our GraphQL API

Insert some fake data into your database to fill the post and comment tables or you can use laravel seeders.

Now that we have a bit of insight into how Lighthouse uses our schema to create queries, let’s run our server and start querying data. We’ll start by running our server:

$ php artisan serve

To query a GraphQL endpoint, you could run cURL command in the terminal or a standard client such as Postman. However, to get the full benefits of GraphQL,we will use  GraphQL Playground .So,type in the url of the browser http://localhost:8000/graphql to point GraphQL Playground to our server. On the left side of the editor, we can query for our data.let’s ask for all the posts that we have in the database with:

{
  posts {
    id
    title
    user {
      id
      name
    }
    comments {
      id
      reply
    }
  }
}

this will return a list of posts with all the comments and user information defined upon.

Hope you enjoyed this post, and if you would like to know more visit Lighthouse documentation.

Tags :