Introduction
In modern web development, GraphQL has emerged as a powerful alternative to REST APIs due to its flexibility and efficiency. It allows clients to request specific data they need, reducing over-fetching and under-fetching of data. If you're working with Laravel, the Lighthouse package offers a seamless way to implement GraphQL in your projects. In this post, we'll explore how to set up and use GraphQL in Laravel using the Lighthouse package, and how you can customize your responses, including handling mutations, queries, and more.
What is GraphQL?
GraphQL is a query language for APIs that allows clients to request specific data they need. Unlike REST, where multiple endpoints return different data structures, GraphQL lets you get all the data you need in a single query, enhancing performance and efficiency.
Why Use Lighthouse with Laravel?
Lighthouse is a PHP package that provides an easy way to integrate GraphQL into your Laravel application. With Lighthouse, you can leverage Laravel’s powerful Eloquent ORM and dependency injection while writing GraphQL queries and mutations. This makes building GraphQL APIs faster, more intuitive, and developer-friendly.
Setting Up Lighthouse in Laravel
To get started with Lighthouse, follow these steps:
- Install Lighthouse: You can install Lighthouse via Composer:
composer require nuwave/lighthouse
- Create the GraphQL Schema: Lighthouse uses a
schema.graphql
file, where you define your GraphQL types, queries, and mutations. You can create this file under thegraphql/
directory:
resources/graphql/schema.graphql
- This GraphQL schema defines various queries and mutations that extend and manipulate
User
andNote
types in a Laravel application using the Lighthouse package. Here’s a breakdown of the key parts of your schema:
#import user.graphql
#import note.graphql
#import auth.graphql
- These lines import other GraphQL files (
user.graphql
,note.graphql
, andauth.graphql
), likely containing additional schema definitions related to users, notes, and authentication whereas this file will contain all the queries, mutations, and types related to theUser
entity.type User { id: ID! name: String! email: String! email_verified_at: String avatar: String notes: [Note]! @hasMany } extend type Query { users: [User!]! @paginate user(id: ID @eq): User @find users(name: String @where(operator: "like")): [User!]! @paginate userNameID(id: ID @eq, name: String @eq): User @find userState(id: ID!): String @field(resolver: "UserStatus@resolve") } extend type Mutation { createUser( name: String! email: String! @rules(apply: ["email", "unique:users"]) password: String! @rules(apply: ["min:8"]) ): User! @create updateUser(id: ID!, name: String, email: String): User! @update deleteUser(id: ID!): User @delete upsertUser( id: ID! name: String! email: String! password: String! ): User! @upsert }
- This file will contain the schema for the
Note
entity, including queries and the type definition forNote
.
type Note {
id: ID!
title: String!
content: String!
user_id: ID!
author: User!
}
extend type Query {
notes: [Note!]! @paginate
note(id: ID @eq): Note @find
}
- This file will handle authentication-related operations, such as login and fetching the authenticated user.
extend type Mutation {
login(email: String!, password: String!, device: String!): String!
}
extend type Query {
me: User! @guard @auth
}
- Resolvers for Custom Logic: You can use resolver classes to handle custom logic, such as checking if a user exists or responding with a specific message. Here’s an example for checking user availability:
<?php
namespace App\GraphQL\Queries;
use App\Models\User;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
class UserStatus
{
public function resolve($rootValue,array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
// fetch a user based on an 'id' argument
$user = User::find($args['id']);
// Check if the user exists
if ($user) {
return "Hi, " . $user->name . " is here.";
} else {
return "User is not available. Bye.";
}
}
}
- This logic can be called via the following query:
query {
userState(id: 1) {
message
user {
id
name
email
}
}
}
- The following mutation handles the Login authentication whereas which uses Laravel Sanctum to create tokens :
<?php
namespace App\GraphQL\Mutations;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
class Login
{
/**
* @param $_
* @param array $args
* @return mixed
* @throws ValidationException
*/
public function __invoke($_, array $args)
{
$user = User::where('email', $args['email'])->first();
if (!$user || !Hash::check($args['password'], $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
return $user->createToken($args['device'])->plainTextToken;
}
}
In the steps above, we've walked through setting up authentication, resolvers, mutations, and other key elements for handling user and note functionality in Laravel using the Lighthouse package. These implementations are explored in the following repository, which contains examples on how the models and seeders are created. You can visit the repository via the link below to see how everything is structured, including how to build queries and mutations.
By clicking on the link provided for the repo, you'll be able to look at the complete codebase and see the Models and Seeders in action. The repository also includes further examples of queries used for testing , allowing you to get hands-on with the GraphQL API. Here are some example queries and mutations you can use to test,
# Query to check the state of a user by ID
query {
userState(id: 100)
}
# Mutation to log in a user
mutation {
login(
email: "info@bishrulhaq.com"
password: "password"
device: "iPhone"
)
}
# Mutation to create a new user
mutation {
createUser(
name: "Test Bishrul Haq"
email: "hellohaq@gmail.com"
password: "secretishere"
) {
id
name
email
}
}
# Mutation to update an existing user
mutation {
updateUser(
id: "1"
name: "John Smith"
email: "johnsmith@example.com"
) {
id
name
email
}
}
# Mutation to upsert (update or insert) a user
mutation {
upsertUser(
id: "1"
name: "Jane Doe"
email: "janedoe@example.com"
password: "newpassword"
) {
id
name
email
}
}
# Query to fetch a list of notes with pagination
query {
notes(first: 10) {
data {
id
title
content
author {
name
email
}
}
paginatorInfo {
currentPage
lastPage
total
}
}
}
Feel free to comment below if you have any questions or run into issues. We'd love to hear your feedback and experiences with using GraphQL and Laravel Lighthouse! Happy coding! 🎉