GraphQL Server With Symfony 4

Get ready with your machine to finish it out
Get ready to implement

To understand this article you need to have some experience of PHP 7.4, Symfony 4, using services and Doctrine ODM with MongoDB. I tried to make code very simple and self explanatory to avoid adding more explanation about code. I also tried to cover more aspects of a real world project e.g. category and its related list products with pagination.

Lets start to setup a GraphQL server using overblog/GraphQLBundle bundle with symfony 4. We will divide it in 4 major parts:

- Installation and configuration of GraphQLBundle.

- Create documents and service to fetch the data.

- Create GraphQL types to define data that can be queried.

- Create Resolver service to resolve all the defined properties.

Installation and configuration of GraphQLBundle

I suppose you have a running application in Symfony 4 with DoctrineMongoDBBundle configured. [Here](https://symfony.com/doc/current/bundles/DoctrineMongoDBBundle/index.html) is a reference to install and configure DoctrineMongoDBBundle in case you are missing it.

Now to install GraphQL Bundle go to your project directory and run following command:

composer require overblog/graphql-bundle

After the installation of dependencies you will get options to execute contrib recipes from symfony flex:

WARNING overblog/graphql-bundle (0.9): From github.com/symfony/recipes-contrib.

You can also enable it manually by:

  1. Enabling bundle
// in config/bundles.php

2. Configuration about schema and types

# in config/packages/graphql.yml

3. And enable GraphQL endpoint

# in config/routes/graphql.yml

Create Document

We will consider the scenario of an e-commerce application in which we will have categories and associated products.

Here is the 2 required documents:

# /src/Document/Categories.php
# /src/Document/Products.php

These are very simple set of document classes and I can expect that you can easily understand it.

Create Service To Fetch Product Data

This service will be used to fetch products of the provided category. You will also notice the implementation of `skip`, `limit` and a function to count all the products of the category. We will use them in the implementation of pagination.

# /src/Product/Provider.php

Create GraphQL Types

Types can be defined in 3 different ways but we will use `configuration way`. See here for more information about all the other ways.

Creating this file extension .types.yaml or .types.xml in /config/graphql/types/.

Lets define the default Query type using yaml files.

# config/graphql/types/Query.types.yaml

It will allow you to make a query for categories which will be resolved using category id that will be an integer.

If you see `type: Categories`, it’s not a built-in type, So we need to define this custom Categories type.

# config/graphql/types/Categories.types.yaml

`resolveField` option is used to invoke class `CategoriesResolver` to resolve all the listed fields ie. name, description, products. GraphQL will call magic method __invoke with following arguments:

- `GraphQL\Type\Definition\ResolveInfo $info` contains the name of the field that will be resolved.

- `$value` is the previously resolved Categories object.

- `Overblog\GraphQLBundle\Definition\Argument $args` ConnectionArguments contains the arguments passed in the query, we will use it in pagination.

Now if you see products property. It is a custom type `ProductConnection`. Here we go for ProductConnection type:

# config/graphql/types/ProductConnection.types.yaml

You might notice the `Connection` suffix in this relay-connection type, If you remove the Connection suffix, it breaks.

Now finally Products type:

# config/graphql/types/Products.types.yaml

It contains all the built-in scalar types. Now no remaining custom types and we have done with types definition.

Create Resolver Service

Now we will define a resolver that will be used to resolve defined properties.

<?php

Here is some details about CategoriesResolver:

- `__invoke()` will be called by GraphQL and will then call a dedicated method to resolve the field.

- `name` and `description` will resolve respective fields.

- `products` resolve the products fields by fetching products based on `$args` which is used to pass pagination related information.

Now you will have a running GraphQL server that will fetch data based on

- Provided Category id from categories collection.

- Fetch associated products from products collection.

- Provide pagination based on provided args.

Lets make query to fetch category details of id#1 with its first:10 products records after:2 records.

/?query={categories(id:1){name,description,products(first:10,after:"YXJyYXljb25uZWN0aW9uOjI="){edges{cursor,node{name,description,price}}}}}

Here `YXJyYXljb25uZWN0aW9uOjI=` is `base64_encode(‘arrayconnection:2’)`. Follow the type-system reference for more details on it.

References

- Introduction to GraphQL

- GraphQL Cursor Connections

- Relay Pagination

- Type System

Software Architect | Developer | Application design | Database design | MongoDB | Golang | PHP | React | Kafka | RabbitMQ | Security Enthusiast