This walkthrough / guide is intended for those who have basic knowledge about building APIs.

GraphQL has been on a hype recently; to be fair, it’s worth it. The need might be quite insidious when building less complex APIs, however, as with all applications, increasing the API capabilities increases complexity in some way and therefore requires a newer approach to handling this complexity without causing pain to the consumers of our API – even when it’s only us.
“A query language for your API”.
This simply means, we have a language with which we can query our API from the front-end (or even back-end). The goal here is to provide us with some consistency and extra power when building APIs. Issues like API versioning can be handled more subtly, thus reducing the need to force users to update their applications for trivial stuff.
For example:
Imagine we had an application with some endpoints: http://localhost:8000/api/v1/rooms
http://localhost:8000/api/v1/make-rooms
http://localhost:8000/api/v1/say-hello
introducing GraphQL, our application now presents just one endpoint:http://localhost:8000/api
All that consumers need to do now is send us a query string on this endpoint; we process the query using GraphQL and respond with data. Quick, intuitive, powerful.
Moving forward….
I want to focus on using GraphQL in PHP as so much explanation already exists for NodeJS (Express) in the official docs for GraphQL.
At this point, you should read the docs to fully understand how GraphQL works before proceeding.
DISCLAIMER:
This is probably not the only valid implementation of GraphQL in PHP. You can choose to explore other options as well.
Set Up
I’ll be using Siler
(a micro-framework with GraphQL functionality built-in) for my stand-alone app, then I’ll show you the set up with my Laravel
app.
Also, it is more comfy to play with GraphQL in the browser using the ChromeiQL extension.
Siler with my stand-alone app
Let’s dive straight into the code. See repo here:
Clone repo into your directory
git clone https://github.com/cmdlucas/siler-gql-play.git
then run
composer install
The project is set up to have two major dependencies in order to listen and respond to GraphQL requests.
webonyx/graphql
– This is the core PHP implementation of the GraphQL standard. It processes the query from the incoming request and responds with the data as specified on our resolvers.
leocavalcante/siler
– This wraps the core package above and adds another major functionality: enables us declareSchema Types
andresolvers
expressively. It basically parses ourSchema Types
declaration string together with theresolvers
array, then sends it to the package above.
To avoid bumping into a class does not exist
type of error, you can run:
composer dump-autoload -o
With our setup completed, we can now run our server and test queries on ChromeiQL
php -S localhost:8000 server.php
Now, start the ChromeiQL extension (ignore any initial error), set the endpoint into http://localhost:8000/api
, then paste this query on the left side of the page loaded:
query Rooms { hello rooms{ key } } mutation MakeRooms ($keys: [ID!]) { makeRooms(keys: $keys) { info { keyToBin timestamp } key } }
Look bottom-left, drag up the area labeled QUERY VARIABLES
and paste this into the text box:
{ "keys": [23, 455, 75, 746] }
When you click the Run button, you have the option to select from the dropdown between Rooms
(which represents the label of query
above) and MakeRooms
(which represents the label of mutation
).
Note: If we were to send this query without using ChromeiQL, we would either want to send the Rooms
query or MakeRooms
mutation. Within either of those, we can specify as many “sub-query” declared within either Query
or Mutation
as supported in the schema in our schema.graphql
file (located in /src/config
).
type Info { keyToBin: String! timestamp: Int! } type Room { info: Info! key: Int! } type Query { hello: String rooms: [Room!]! roomsHavingKey(search_keys : [ID!]!): [Room!]! roomsNotHavingKey(search_keys : [ID!]!): [Room!]! } type Mutation { makeRooms (keys: [ID!]): [Room!]! }
(Go here to see how to send queries over http)
After selecting which type to run, you can see the server’s response is as specified within the query sent. This means we can do so many things in a single query to the server – be it a Query
type or a Mutation
. Alles gut? Okay….
As you can see, within the type Query {}
schema above, we specified roomsHavingKey
and roomsNotHavingKey
, but there was no need to include it in the query sent to the server since we (the caller) did not need any of that information. But hey, let’s try to get that information.
In your ChromeiQL, change the query field’s content to this:
query Rooms($search_keys: [ID!]!) { rooms{ key } roomsNotHavingKey(search_keys: $search_keys) { key info{ keyToBin timestamp } } } mutation MakeRooms ($keys: [ID!]) { makeRooms(keys: $keys) { key } }
In the QUERY VARIABLES
area, change the content to this:
{ "keys": [23, 455, 75, 746], "search_keys": [23, 75] }
To get some result, first we run and select MakeRooms
, then we run and select Rooms
from the dropdown. As a result of the latter action, we get this response from the server:
{ "data": { "rooms": [ { "key": 23 }, { "key": 455 }, { "key": 75 }, { "key": 746 } ], "roomsNotHavingKey": [ { "key": 455, "info": { "keyToBin": "111000111", "timestamp": 1558951933 } }, { "key": 746, "info": { "keyToBin": "1011101010", "timestamp": 1558951933 } } ] } }
This ran just as expected. The rooms
sub-query returns a list of room
objects each with the key
property only. Also, since we specified it too, the roomsNotHavingKey
sub-query returned a list of rooms
with keys other than the keys
in the search_key
list specified in the QUERY VARIABLES
.
We can take this concept to a more complex level, depending on the requirements of our application. This is amazing power lying in our hands at one API endpoint!
Siler GraphQL with Laravel
Here, my goal is just to show you how to easily configure Siler GraphQL with Laravel using the example specified in the README
of the Siler GraphQL package.
Dive straight into testing? Go to repo
Firstly, create a new laravel project into any folder on your computer:
composer create-project --prefer-dist laravel/laravel my_folder
Now, install the dependencies required (which includes those required for GraphQL to be activated):
composer require --prefer-dist leocavalcante/siler webonyx/graphql-php
Navigate to /routes/web.php
and add this:
use Siler\GraphQL; class Init { public static function play() { $typeDefs = file_get_contents(__DIR__.'/schema.graphql'); $resolvers = [ 'Query' => [ 'message' => 'foo', ], 'Mutation' => [ 'sum' => function ($root, $args) { return $args['a'] + $args['b']; }, ], ]; return GraphQL\init(GraphQL\schema($typeDefs, $resolvers)); } } Route::post('/play', function() { return Init::play(); });
Create a schema.graphql
file in the routes folder (could be anywhere else, just make sure you read it using the correct URL) and add this:
type Query { message: String! } type Mutation { sum (a: Int, b: Int): Int }
Run: php artisan serve
Now, we can query from ChromeiQL and get a response. Set your endpoint to http://localhost:8000/play
, paste this into the query field:
query Message { message } mutation Sum($a: Int, $b: Int) { sum(a: $a, b: $b) }
Then this into the QUERY VARIABLES
field:
{ "a": 5, "b": 6 }
When we run and select Sum
, we get this:
{ "data": { "sum": 11 } }
Very straightforward!
If you have questions, additions or corrections, please feel free to comment or send me a message here: https://caleb.lucasbin.com/contact