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)