Ludo237
Ludo237

Reputation: 1717

Lighthouse can't find my custom Types for Union

how are you doing?

I'm struggling with unions I'd like some clarification in regards of custom resolvers for union type based on custom types. Mi current schema is this for product.graphql which is imported inside schema.graphql

type ProductServing {
    name: String
    price: Float
}

type ProductDish {
    price: Float
    calories: Int
    servings: [ProductServing]
}

type ProductDrink {
    price: Float
    servings: [ProductServing]
}

union ProductProperties = ProductDish | ProductDrink

type Product {
    id: ID!
    user: User! @belongsTo
    media: Media
    blocks: [Block]! @belongsToMany
    slug: String!
    name: String!
    description: String
    properties: ProductProperties!
    activated_at: DateTime
    created_at: DateTime!
    updated_at: DateTime!
} 

Of course this schema alone wont work because Lighthouse cannot understand the custom type. I've created two classes for Types:

// App\GraphQL\Types
class ProductDish extends ObjectType
{
    public function __construct()
    {
        $config = [
            "name" => "ProductDish",
            "fields" => [
                "__type" => Type:string(),
                "price" => Type::float(),
                "calories" => Type::int(),
            ],
        ];
        parent::__construct($config);
    }
}

class ProductDrink extends ObjectType
{
    public function __construct()
    {
        $config = [
            "name" => "ProductDrink",
            "fields" => [
                "__type" => Type:string(),
                "price" => Type::float(),
            ],
        ];
        parent::__construct($config);
    }
}

And a union class for ProductProperties which use the __invoke method

// App\GraphQL\Unions;
public function __invoke($rootValue, GraphQLContext $context, ResolveInfo $resolveInfo) : Type
{
    $type = $rootValue["__type"];
    switch ($type) {
        case "dish" :
            return $this->typeRegistry->get(ProductDish::class);
        case "drink":
            return $this->typeRegistry->get(ProductDrink::class);
    }
    return $this->typeRegistry->get(class_basename($rootValue));
}

This doesn't work, otherwise I wouldn't be here, looking at the graphql-playground I get this message

"debugMessage": "Lighthouse failed while trying to load a type: App\\GraphQL\\Types\\ProductDish\n\nMake sure the type is present in your schema definition.\n"

The thing is that I'm not sure if 1) this is the right approach 2) why lighthouse can't load the type.

Can you show me the correct way of handling this?

Bear in mind that

Upvotes: 2

Views: 1441

Answers (1)

Ludo237
Ludo237

Reputation: 1717

I was on the right track but I needed to fix some things

First, inside ProductProperties file the registry expect a simple string not a namespace so I had to type ->get("ProductDish") instead of ->get(ProductDish::class) then I removed the __type field inside my types, and graphql schemas because I can use a mutator inside Product model and determine which type is based on some parameters, something like this

public function getPropertisAttribute($properties) {
    
   $properties = json_decode($properties, true);

   $properties["__type"] = // .. some logic to get the right type

   return $properties;
}

Once I've a type I can use that back into my ProductProperties union class

Upvotes: 1

Related Questions