Get Started with GraphQL and Laravel
GraphQL is a powerful REST alternative that allows developers to build APIs. We will be using GraphQL to create a simple CRUD application that allows us to create, read, update and delete data.
Setup the project
Prerequisites
Create new Laravel Project
Use composer to create a new Laravel project by running:
composer create-project --prefer-dist laravel/laravel graphql-basics
Install Laravel Sail
We will be using Laravel Sail to run our local environment. Sail allows us to seamlessly run Docker without complex configuration
composer require laravel/sail --dev
php artisan sail:install
Select [0]
the mysql service
Start Docker
Create a sail shortcut:
alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'
Start Sail & Docker:
sail up -d
Install GraphQL Laravel library
The most popular GraphQL libraries for Laravel are Rebing & Lighthouse, in our tutorial we will be using Rebing
which we can install by running:
composer require rebing/graphql-laravel
Then publish the config file
sail artisan vendor:publish --provider="Rebing\\GraphQL\\GraphQLServiceProvider"
Prepare database migrations & models
Run the following command to create the Company model, migration and factory:
sail artisan make:model Company -m -f
Migration
Edit the generated migration file by replacing its content with the following:
<?php
use Illuminate\\Database\\Migrations\\Migration;
use Illuminate\\Database\\Schema\\Blueprint;
use Illuminate\\Support\\Facades\\Schema;
class CreateCompaniesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('contact_email');
$table->string('street_address');
$table->string('city');
$table->string('country');
$table->string('domain');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('companies');
}
}
Model
Now, add these fields as $fillable
properties for the Company model.
<?php
namespace App\\Models;
use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
use Illuminate\\Database\\Eloquent\\Model;
class Company extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var string[]
*/
protected $fillable = [
'name',
'contact_email',
'street_address',
'city',
'country',
'domain'
];
}
Factory
Let's create our Company factory for seeding purposes.
<?php
namespace Database\\Factories;
use Illuminate\\Database\\Eloquent\\Factories\\Factory;
class CompanyFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->company,
'contact_email' => $this->faker->companyEmail,
'street_address' => $this->faker->streetAddress,
'city' => $this->faker->city,
'country' => $this->faker->country,
'domain' => $this->faker->domainName
];
}
}
Update Database Seeder
<?php
namespace Database\\Seeders;
use App\\Models\\Company;
use Illuminate\\Database\\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
Company::factory(10)->create();
}
}
Migrate & Seed Database
Run this command to seed our database:
sail artisan migrate --seed
Build our GraphQL Server
Let's start defining our GraphQL schema
Create GraphQL Type for Company
Run the following command to create our GraphQL type:
sail artisan make:graphql:type CompanyType
Then navigate to the app/GraphQL/Types
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Types;
use App\\Models\\Company;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Type as GraphQLType;
class CompanyType extends GraphQLType
{
protected $attributes = [
'name' => 'Company',
'description' => '',
'model' => Company::class
];
public function fields(): array
{
return [
'id' => [
'type' => Type::id(),
'description' => 'The auto incremented ID of a company'
],
'name' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The name of a company'
],
'contact_email' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The primary point of contact for a company'
],
'street_address' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The street address of a company headquarters'
],
'city' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The city of a company headquarters'
],
'country' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The country of a company headquarters'
],
'domain' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The web domain for a company'
]
];
}
}
Create GraphQL Queries
Queries will be used to retrieve data from the database.
CompanyQuery
Run the following to create the company query:
sail artisan make:graphql:query CompanyQuery
Then navigate to the app/GraphQL/Queries
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Queries;
use App\\Models\\Company;
use Closure;
use GraphQL\\Type\\Definition\\ResolveInfo;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Facades\\GraphQL;
use Rebing\\GraphQL\\Support\\Query;
use Rebing\\GraphQL\\Support\\SelectFields;
class CompanyQuery extends Query
{
protected $attributes = [
'name' => 'company'
];
public function type(): Type
{
return GraphQL::type('Company');
}
public function args(): array
{
return [
'id' => [
'name' => 'id',
'type' => Type::id(),
'rules' => ['required']
],
];
}
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields)
{
return Company::findOrFail($args['id']);
}
}
CompaniesQuery
Run the following to create the companies query:
sail artisan make:graphql:query CompaniesQuery
Then navigate to the app/GraphQL/Queries
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Queries;
use App\\Models\\Company;
use Closure;
use GraphQL\\Type\\Definition\\ResolveInfo;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Facades\\GraphQL;
use Rebing\\GraphQL\\Support\\Query;
use Rebing\\GraphQL\\Support\\SelectFields;
class CompaniesQuery extends Query
{
protected $attributes = [
'name' => 'companies'
];
public function type(): Type
{
return Type::listOf(GraphQL::type('Company'));
}
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields)
{
return Company::all();
}
}
Create the GraphQL Mutations
Mutations are used insert, update, and delete an entity.
Create Company Mutation
Run the following command to create new mutation:
sail artisan make:graphql:mutation CreateCompanyMutatio
Then navigate to the app/GraphQL/Mutations
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Mutations;
use App\\Models\\Company;
use Closure;
use GraphQL\\Type\\Definition\\ResolveInfo;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Facades\\GraphQL;
use Rebing\\GraphQL\\Support\\Mutation;
use Rebing\\GraphQL\\Support\\SelectFields;
class CreateCompanyMutation extends Mutation
{
protected $attributes = [
'name' => 'createCompany'
];
public function type(): Type
{
return GraphQL::type('Company');
}
public function args(): array
{
return [
'name' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The name of a company'
],
'contact_email' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The primary point of contact for a company',
'rules' => ['email']
],
'street_address' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The street address of a company headquarters'
],
'city' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The city of a company headquarters'
],
'country' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The country of a company headquarters'
],
'domain' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The web domain for a company'
]
];
}
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields)
{
return Company::create($args);
}
}
Update Company Mutation
Run the following command to create new mutation:
sail artisan make:graphql:mutation UpdateCompanyMutation
Then navigate to the app/GraphQL/Mutations
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Mutations;
use App\\Models\\Company;
use Closure;
use GraphQL\\Type\\Definition\\ResolveInfo;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Facades\\GraphQL;
use Rebing\\GraphQL\\Support\\Mutation;
use Rebing\\GraphQL\\Support\\SelectFields;
class UpdateCompanyMutation extends Mutation
{
protected $attributes = [
'name' => 'updateCompany'
];
public function type(): Type
{
return GraphQL::type('Company');
}
public function args(): array
{
return [
'id' => [
'name' => 'id',
'type' => Type::nonNull(Type::int()),
],
'name' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The name of a company'
],
'contact_email' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The primary point of contact for a company',
'rules' => ['email']
],
'street_address' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The street address of a company headquarters'
],
'city' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The city of a company headquarters'
],
'country' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The country of a company headquarters'
],
'domain' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The web domain for a company'
]
];
}
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields)
{
$company = Company::findOrFail($args['id']);
$company->update($args);
return $company->refresh();
}
}
Delete Company Mutation
Run the following command to create new mutation:
sail artisan make:graphql:mutation DeleteCompanyMutation
Then navigate to the app/GraphQL/Mutations
directory and modify the file like so:
<?php
declare(strict_types=1);
namespace App\\GraphQL\\Mutations;
use App\\Models\\Company;
use Closure;
use GraphQL\\Type\\Definition\\ResolveInfo;
use GraphQL\\Type\\Definition\\Type;
use Rebing\\GraphQL\\Support\\Mutation;
use Rebing\\GraphQL\\Support\\SelectFields;
class DeleteCompanyMutation extends Mutation
{
protected $attributes = [
'name' => 'deleteCompany'
];
public function type(): Type
{
return Type::boolean();
}
public function args(): array
{
return [
'id' => [
'name' => 'id',
'type' => Type::id(),
],
];
}
public function resolve($root, array $args, $context, ResolveInfo $resolveInfo, Closure $getSelectFields)
{
$company = Company::findOrFail($args['id']);
return $company->delete();
}
}
Load Schema
We need to register to schema within the GraphQL configuration file, located at config/graphql.php
:
'schemas' => [
'default' => [
'query' => [
// ExampleQuery::class,
\\App\\GraphQL\\Queries\\CompanyQuery::class,
\\App\\GraphQL\\Queries\\CompaniesQuery::class
],
'mutation' => [
// ExampleMutation::class,
\\App\\GraphQL\\Mutations\\CreateCompanyMutation::class,
\\App\\GraphQL\\Mutations\\UpdateCompanyMutation::class,
\\App\\GraphQL\\Mutations\\DeleteCompanyMutation::class
],
// The types only available in this schema
'types' => [
\\App\\GraphQL\\Types\\CompanyType::class
],
// Laravel HTTP middleware
'middleware' => null,
// Which HTTP methods to support; must be given in UPPERCASE!
'method' => ['GET', 'POST'],
// An array of middlewares, overrides the global ones
'execution_middleware' => null,
],
],
Run the Application
Since we already started the app using Sail, we can go to the url: http://localhost/graphiql to test our endpoints
Return all companies
{
companies {
id
name
contact_email
street_address
city
country
domain
}
}
Return single company
{
company(id:1) {
id
name
contact_email
street_address
city
country
domain
}
}
Create company
mutation {
createCompany(name:"Apple Inc.", contact_email:"support@apple.com",
street_address:"One Apple Park Way", city: "Cupertino", country:"USA", domain:"apple.com") {
name
domain
}
}
Update Company
mutation {
updateCompany(id: 3, name: "Facebook Inc.", contact_email: "support@facebook.com",
street_address:"1 Hacker Way, Menlo Park", city: "Menlo Park", country: "USA",
domain: "facebook.com") {
name
domain
}
}
Delete Company
mutation {
deleteCompany(id: 7)
}
Recap
In conclusion, GraphQL is a very powerful tool for building modern APIs. If you found this tutorial useful, considering subscribing to my YouTube channel where I record
programming content on the regular.
Top comments (0)