Les resolvers GraphQL

Les resolvers GraphQL

22 octobre 2021

Un resolver permet de récupérer les données en base de données via une requête. Vous avez besoin d'autant de resolvers que de schemas.

Sous Symfony, vous pouvez soit utiliser les services de Symfony, soit les créer vous-même. Nous allons utiliser les services mise à notre disposition grâce aux interfaces ResolverInterface et AliasedInterface.

Dans notre fichier Query.yaml, nous allons ajouter les resolvers nécessaires au bon fonctionnement. Mettez à jour le fichier :

Query:
    type: object
    config:
        fields:
            Artist:
                type: 'Artist'
                args:
                    id:
                        description: 'Resolves Artist using its id.'
                        type: 'Int!'
                resolve: "@=resolver('Artist', [args['id']])"
            Artists:
                type: '[Artist]'
                resolve: "@=resolver('Artists')"
            Album:
                type: 'Album'
                args:
                    id:
                        description: 'Resolves Album using its id.'
                        type: 'Int!'
                resolve: "@=resolver('Album', [args['id']])"
            Albums:
                type: '[Album]'
                resolve: "@=resolver('Albums')"

Maintenant que nos requêtes sont prêtes, nous allons créer les resolvers dans Symfony. Pour cela, créez le dossier Resolver dans le dossier src/GraphQL. Il y aura autant de resolvers que nécessaire. Dans notre cas de figure, nous en aurons besoin de quatre :

  • Récupérer tous nos artistes
  • Récupérer un artiste selon un ID
  • Récupérer tous nos albums
  • Récupérer un album selon un ID

Notre premier fichier sera ArtistResolver.php :

<?php

namespace App\GraphQL\Resolver;

use App\Entity\Artist;
use App\Repository\ArtistRepository;
use Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;

class ArtistResolver implements ResolverInterface, AliasedInterface
{
    /**
     * @var ArtistRepository
     */
    private ArtistRepository $artistRepository;

    /**
     *
     * @param ArtistRepository $artistRepository
     */
    public function __construct(ArtistRepository $artistRepository)
    {
        $this->artistRepository = $artistRepository;
    }

    /**
     * @return Artist
     */
    public function resolve(int $id)
    {
        return $this->artistRepository->find($id);
    }

    /**
     * {@inheritdoc}
     */
    public static function getAliases(): array
    {
        return [
            'resolve' => 'Artist',
        ];
    }
}

Nous retrouvons différentes parties comme le constructeur qui récupère le repository nécessaire à la sélection de notre artiste.
La méthode resolve(int $id) ayant en argument un $id possédant une demande au repository afin de retourner un artiste selon son ID et enfin une méthode function getAliases() afin de relier notre resolver à la clé de notre requête GraphQL.

Voici les derniers resolvers :

ArtistsResolver.php :

<?php

namespace App\GraphQL\Resolver;

use App\Entity\Artist;
use App\Repository\ArtistRepository;
use Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;

class ArtistsResolver implements ResolverInterface, AliasedInterface
{
    /**
     * @var ArtistRepository
     */
    private ArtistRepository $artistRepository;

    /**
     *
     * @param ArtistRepository $artistRepository
     */
    public function __construct(ArtistRepository $artistRepository)
    {
        $this->artistRepository = $artistRepository;
    }

    /**
     * @return Artist[]
     */
    public function resolve()
    {
        return $this->artistRepository->findAll();
    }

    /**
     * {@inheritdoc}
     */
    public static function getAliases(): array
    {
        return [
            'resolve' => 'Artists',
        ];
    }
}

AlbumResolver.php :

<?php

namespace App\GraphQL\Resolver;

use App\Entity\Album;
use App\Repository\AlbumRepository;
use Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;

class AlbumResolver implements ResolverInterface, AliasedInterface
{
    /**
     * @var AlbumRepository
     */
    private AlbumRepository $albumRepository;

    /**
     *
     * @param AlbumRepository $albumRepository
     */
    public function __construct(AlbumRepository $albumRepository)
    {
        $this->albumRepository = $albumRepository;
    }

    /**
     * @return Album
     */
    public function resolve(int $id)
    {
        return $this->albumRepository->find($id);
    }

    /**
     * {@inheritdoc}
     */
    public static function getAliases(): array
    {
        return [
            'resolve' => 'Album',
        ];
    }
}

AlbumsResolver.php :

<?php

namespace App\GraphQL\Resolver;

use App\Entity\Album;
use App\Repository\AlbumRepository;
use Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;

class AlbumsResolver implements ResolverInterface, AliasedInterface
{
    /**
     * @var AlbumRepository
     */
    private AlbumRepository $albumRepository;

    /**
     *
     * @param AlbumRepository $albumRepository
     */
    public function __construct(AlbumRepository $albumRepository)
    {
        $this->albumRepository = $albumRepository;
    }

    /**
     * @return Album[]
     */
    public function resolve()
    {
        return $this->albumRepository->findAll();
    }

    /**
     * {@inheritdoc}
     */
    public static function getAliases(): array
    {
        return [
            'resolve' => 'Albums',
        ];
    }
}

Maintenant que nos resolvers sont prêts, faisons un nouvel essai dans GraphiQL :

{
  Artists {
    firstname
  }
}

La réponse :

{
    "data": {
        "Artists": [
            {
                "firstname": "Adriano"
            },
            {
                "firstname": "Dagmar"
            },
            {
                "firstname": "Tiebold"
            }
        ]
    }
}

Tout fonctionne parfaitement !

Terminons avec un essai en demandant l'album portant l'ID numéro 1 :

{
  Album(id: 1) {
    title
    artist {
      firstname
    }
  }
}

Résultat :

{
  "data": {
    "Album": {
      "title": "Utopie",
      "artist": {
        "firstname": "Jane"
      }
    }
  }
}

Il est dorénavant possible d'effectuer toutes les sélections que nous voulons avec les données que nous souhaitons.