| Q | A
| ---------------- | -----
| Bug report? | yes
| Feature request? | no
| BC Break report? | no
| RFC? | no
| Version/Branch | 0.9.1
Hello everyone,
As described in the symfony/recipes-contrib repository, I've tried to install the bundle using the recipes allowed, I've finally succeeded to create types and schema but I met a problem with the resolvers, here's the problem.
I've defined an ImageResolver who's responsible for resolving all the images (or a single one) stored in the BDD (PostgreSQL via Doctrine), here's the class :
<?php
/*
* This file is part of the MarketReminder project.
*
* (c) Guillaume Loulier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Resolvers;
use App\Models\Image;
use Doctrine\ORM\EntityManagerInterface;
use Overblog\GraphQLBundle\Definition\Argument;
use Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface;
/**
* Class ImageResolver
*
* @author Guillaume Loulier <[email protected]>
*/
class ImageResolver implements ResolverInterface
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* ImageResolver constructor.
*
* @param EntityManagerInterface $entityManagerInterface
*/
public function __construct(EntityManagerInterface $entityManagerInterface)
{
$this->entityManager = $entityManagerInterface;
}
/**
* @param Argument $argument
*
* @return Image|Image[]|array|null|object
*/
public function getImage(Argument $argument)
{
if ($id = $argument->offsetExists('id')) {
return $this->entityManager->getRepository(Image::class)
->findOneBy([
'id' => $id
]);
}
return $this->entityManager->getRepository(Image::class)->findAll();
}
}
As define in the documentation, here's my services.yml :
parameters:
locale: 'en'
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Repository}'
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
graphql.image_resolver:
class: App\Resolvers\ImageResolver
arguments:
- '@doctrine.orm.entity_manager'
tags:
- { name: overblog_graphql.resolver, alias: 'image_id', method: 'getImage' }
The tag seems good and the method call is exactly like the method declaration, in accord with the documentation, here's the query.yaml file :
Query:
type: object
config:
description:
fields:
user:
type: "User"
description: "An user registered into the application"
args:
id:
type: "Int"
description: "The id of the User"
resolve: "@resolver=('user_id', [args])"
image:
type: "Image"
description: "An image linked to an user"
args:
id:
type: "Int"
description: "The id of the Image"
resolve: "@marketReminder.graphql.image_resolver=('image_id', [args])"
stock:
type: "Stock"
description: "A stock saved and linked to an user"
args:
id:
type: "Int"
description: "The id of the Stock"
resolve: "@resolver=('stock_id', [args])"
products:
type: "Products"
description: "A product saved and linked to a stock"
args:
id:
type: "Int"
description: "The id of the product"
resolve: "@resolver=('products_id', [args])"
As you can see, the resolve is called in the Image definition and he must return the image(s) as defined in the resolver, problem is, if I use the /graphiql endpoint and ask for something like this :
{
image(id: 1) {
alt
}
}
Here's the return :
{
"data": {
"image": {
"alt": null
}
}
}
The fixtures is loaded and the PHPStorm interface return data into the BDD so I guess the problem comes from the resolver or the bundle linking process between the requested resource and the endpoint return.
I know that I can ask in the symfony-devs Slack but it seems that no one has use the bundle since he's allowed by Flex so I come here to have the "creator" vision for my problem, I know it's not really an issue and more a "configuration" or "classe definition" problem but it really block me and I don't know how to solve this problem.
Plus, I've read the documentation for days and I find that the resolver part it's not pretty clear, the ResolverInterface is empty (who's strange for an interface ?) and there's not example in order to build a simple resolver, maybe this part can be completed ?
Thanks again for the help and have a great day :).
Hi,
It look like your resolver returns a collection while your Schema expects a single Image.
image:
type: "Image"
description: "An image linked to an user"
args:
id:
type: "Int"
description: "The id of the Image"
resolve: "@marketReminder.graphql.image_resolver=('image_id', [args])"
Have you define a custom expression language objet marketReminder?
Also sorry for the wait...
Hi @mcg-web, no problem for the wait.
Yes, after looking at my code, I found that my resolvers are badly declared, here's the new services.yml :
parameters:
locale: 'en'
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Repository}'
App\Action\:
resource: '../src/Action'
tags: ['controller.service_arguments']
graphql.image_resolver:
class: App\Resolvers\ImageResolver
arguments:
- '@doctrine.orm.entity_manager'
tags:
- { name: overblog_graphql.resolver, alias: 'image_resolver', method: getImage }
graphql.user_resolver:
class: App\Resolvers\UserResolver
arguments:
- '@doctrine.orm.entity_manager'
tags:
- { name: overblog_graphql.resolver, alias: 'user_resolver', method: getUser }
- { name: overblog_graphql.resolver, alias: 'users_resolver', method: getUsers }
graphql.stock_resolver:
class: App\Resolvers\StockResolver
arguments:
- '@doctrine.orm.entity_manager'
tags:
- { name: overblog_graphql.resolver }
graphql.products_resolver:
class: App\Resolvers\ProductsResolver
arguments:
- '@doctrine.orm.entity_manager'
tags:
- { name: overblog_graphql.resolver }
graphql.user_mutator:
class: App\Mutators\UserMutator
tags:
- { name: overblog_graphql.mutation, method: register }
- { name: overblog_graphql.mutation, method: login }
- { name: overblog_graphql.mutation, method: forgotPassword }
- { name: overblog_graphql.mutation, method: dropUser }
graphql.image_mutator:
class: App\Mutators\ImageMutator
tags:
- { name: overblog_graphql.mutation, alias: 'image_creation', method: createImage }
graphql.stock_mutator:
class: App\Mutators\StockMutator
tags:
- { name: overblog_graphql.mutation, alias: 'stock_creation', method: createStock }
The alias key is mandatory (this could be added to the documentation because, without this key, the "@=service" call is mandatory in order to make the resolver work as expected) as I saw from here.
After this, here's the query.yaml :
```yml
Query:
type: object
config:
description:
fields:
user:
type: "User"
description: "An user registered into the application"
args:
id:
type: "Int"
description: "The id of the User, if omitted, return all the users."
resolve: "@=resolver('user_resolver', [args])"
users:
type: "[User]"
description: "All the users saved."
resolve: "@=resolver('users_resolver')"
image:
type: "[Image]"
description: "An image linked to an user"
args:
id:
type: "Int"
description: "The id of the Image, if omitted, all the images are returned."
resolve: "@=resolver('image_resolver', [args])"
stock:
type: "[Stock]"
description: "A stock saved and linked to an user"
args:
id:
type: "Int"
description: "The id of the Stock"
resolve: "@=service('graphql.stock_resolver').getStock(args)"
products:
type: "[Products]"
description: "A product saved and linked to a stock, if omitted, return all the stocks"
args:
id:
type: "Int"
description: "The id of the product, if omitted, return all the products."
resolve: "@=service('graphql.products_resolver').getProduct(args)"
````
Using this approach (the service call for stock and products are just for placeholding), I can reach the resolver and get all the images or a single one (thanks to Youtube -
API GraphQL, you can return a single occurence using the [] approach).
For the documentation, it could be usefull to update the docs according to a practical example, don't know exactly what but an example using a Foo object or even an Article can help to configure the bundle.
PS : Yes, for the marketReminder object, it was an error.
No alias should not be a mandatory, when not using alias key the alias is the fully qualified method name (example: AppBunble\GraphQL\CustomResolver::myMethod) if this is not the case this is a bug. Yes I agree that the doc can be perfected, all contribution is welcome.
After reconfiguring my resolvers, I can assure that the alias is "mandatory", if not defined, the resolver isn't found.
For the documentation, yes, definitively gonna look for adding more "examples" and explanation about the configuration and definition part :)
@mcg-web
No alias should not be a mandatory, when not using alias key the alias is the fully qualified method name (example: AppBunble\GraphQL\CustomResolver::myMethod) if this is not the case this is a bug.
in my case I have next config of services:
services:
App\GraphQL\Resolver\:
resource: '../src/GraphQL/Resolver'
tags: ['overblog_graphql.resolver']
and I'm trying to use resolver
Query:
type: object
config:
description: "Users"
fields:
user:
type: "User"
args:
id:
type: "Int"
resolve: "@=resolver('\\App\\GraphQL\\Resolver\\UserResolver', [args['id']])"
UserResolver.php
class UserResolver
{
private static $users = [
1 => ['id' => 1, 'username' => 'Sasha'],
2 => ['id' => 2, 'username' => 'Dima'],
];
public function __invoke($data)
{
if (isset(self::$users[$data])) {
return self::$users[$data];
}
return null;
}
}
but have exception
Unknown resolver with alias \"AppGraphQLResolverUserResolver\" (verified service tag)
@Besedin86
What if you use :
@=resolver("App\GraphQL\Resolvers\UserResolver", [args])
Seems like the namespace call isn't good.
Yaml format will be not valid. I tried different ways
This solution should works with simple quote '@=resolver("App\GraphQL\Resolvers\UserResolver", [args])'
Also no need to declare resolver if you using 0.9 version it is auto-configure...
This solution should works with simple quote '@=resolver("App\GraphQL\Resolvers\UserResolver", [args])'
No luck. Have the same exception. It cleanups FQCN from backslashes
can you try this please '@=resolver(\'App\\GraphQL\\Resolvers\\UserResolver\', [args])'
only example I found in the code add slashes like this. but the best solution is to implements interface Resolver aliases (Overblog\GraphQLBundle\Definition\Resolver\ResolverInterface and Overblog\GraphQLBundle\Definition\Resolver\AliasedInterface) and use it in expression language see https://github.com/overblog/GraphQLBundle/blob/master/Resources/doc/definitions/resolver.md so no need to load your resolvers like this.
services:
App\GraphQL\Resolver\:
resource: '../src/GraphQL/Resolver'
tags: ['overblog_graphql.resolver']
can you try this please '@=resolver(\'App\GraphQL\Resolvers\UserResolver\', [args])'
This is not valid YAML format;
I worked around this and found in \Overblog\GraphQLBundle\__DEFINITIONS__\QueryType::__constructor()
next definition
return $container->get('overblog_graphql.resolver_resolver')->resolve(["AppGraphQLResolversUserResolver", array(0 => $args)]);
Maybe it helps you
so no need to load your resolver like this.
I removed this from my services configuration, but result is the same.
I use Symfony 4.0-Beta1 and bundle v0.10.0@dev
Finally I found mistake in my definition.
The final solution is
'@=resolver("App\\GraphQL\\Resolver\\UserResolver", [args])'
(define Resolver without "s" :man_facepalming: )
and resolver class I implement from definition Resolver interface.
This time all works as expected. Thanks
@Guikingone I added tests to cover no alias and no method for invokable classes using configuration. I confirm that It works correctly in #239
I'm closing this, reopen if needed :+1:
Most helpful comment
Finally I found mistake in my definition.
The final solution is
(define Resolver without "s" :man_facepalming: )
and resolver class I implement from definition Resolver interface.
This time all works as expected. Thanks