Florent Destremau

A history of Symfony and GraphQL

You might have heard of a new sheriff in town: GraphQL. And then wondered how you could use it with *insert your non-JS language here*.

TLDR;

If you are very lazy and just want a solution, here is my demo project, Iā€™ll try to keep it updated: https://github.com/florentdestremau/graphql-example

What is GraphQL? Small reminder

Quick memo for those who donā€™t know what Iā€™m talking about: GraphQL is a query language designed by Facebook to represent a modern way to communicated data between your front-end and back-end. For example if you wanted to query for the latest article from a blog, youā€™d write something like this as a front-end query

articles(limit: 10) {  
  id  
  title  
  excerpt  
  categories {  
    id  
    name  
  }  
  comments(limit: 3) {  
    id  
    author {  
      id  
      name  
    }  
    content  
  }  
}

Did you see what happened here? A whole hierarchy of information was requested in a single request, and now we have all the information needed to display a whole bunch of stuff:

So this is the very basic usage of GraphQL. But itā€™s only half of the implementation, you still need the back-end to handle the query interpretation and then return the actual data.

The back-end implementation in Symfony

If you are convinced by the simplicity and power of this type of query from the front-end (I sure am!), you probably wonder how it turns out in your back-end. So now is the time for me to announce that I am a Symfony developper and thus, while Facebook gave plenty of tools for NodeJS lovers, I had to rely on other libraries.

Meet youshido/graphql-bundle, the bundle that makes it all easy for you !

Note: there is an php port linked on the GraphQL website but at the time I was looking for a Symfony implementation, the youshido bundle was a better option for me, feel free to try the PHP library out !

The objective of this article is to explain how we use this bundle to easily set up you GraphQL API for a simple use: front-end widgets. The YoushidoGraphQLBundleprovides several classes to structure your GraphQL query tree.

For example you will have a tree structure like this:

Schema  
  - Query  
    - ArticlesField  
    - CommentsField  
    - UsersField  
    - CategoriesField  
  - Mutations  
    - PostArticleField

And each of these Fields will respectively return ArticleType, CommentType, UserType, CategoryType, or more exactly aListType of these.

The Fields

Here is what a simple ArticlesField would look like.

class ArticlesField extends AbstractContainerAwareField  
{  
    public function resolve($value, array $args, ResolveInfo $info)  
    {  
        return $this->container->get('doctrine.orm.entity\_manager')->getRepository(Article::class)->findAll();  
    } public function getType()  
    {  
        return new ListType(new ArticleType());  
    }  
}

Notice the 2 key functions here.

There is an extra function that you can use, itā€™s the build function:

public function build(FieldConfig $config)  
{  
   $config->addArguments(  
       \[  
           'published'  => new BooleanType(),  
       \]  
   );  
}

This argument is exposed to the query, for instance you could query only articles that are published

articles(published: true) {  
  id  
  title  
  body  
}

And then you can update your resolver:

public function resolve($value, array $args, ResolveInfo $info)  
{  
    return $this->container  
      ->get('doctrine.orm.entity\_manager')  
      ->getRepository(Article::class)  
      ->findBy(\[  
        'published' => $args\['published'\],  
      \]);  
}

And there you go, filtered results !

The Types

So this was the ā€œcontrollerā€ part of the query, and now letā€™s get to the ā€œtemplatingā€ part. The Types (kind of a unfortunate naming, in my opinion, with the form Types as well, but hey I didnā€™t write it ĀÆ\_(惄)_/ĀÆ) are the classes that defines the JSON output for the file. Here is an example of what the ArticleType would be.

class ArticleType extends AbstractObjectType  
{  
    public function build($config)  
    {  
        $config->addFields(  
            \[  
                'id'         => new IdType(),  
                'title'      => new StringType(),  
                'body'       => new StringType(),  
                'categories' => new ListType(new CategoryType()),  
            \]  
        );  
    }  
}

This way you define what fields are available to retrieve. Now this is a simple version, but you can add custom fields that require a bit more of an assistance. For instance to display the phone number of a user I would need to use the container:

As you can see the ResolveInfo entity has access to the container so you can use different services to render or simply do some logic stuff.

And there you go, a full GraphQL API!

Oh and one last thing, did I tell you that you had a live explorer at the /graphql/explorer ?

I actually made an API boilerplate with the bundle already installed:

florentdestremau/graphql-example

Liked what you read ? Hit the šŸ‘ button, I will write some more!