Search code examples
graphqlgraphql-php

getting started in graphql-php: how to add resolver functions to schema from .graphql file?


I'm totally new to GraphQL and wanted to play around with graphql-php in order to build a simple API to get started. I'm currently reading the docs and trying out the examples, but I'm stuck quite at the beginning.

I want my schema to be stored in a schema.graphql file instead of building it manually, so I followed the docs on how to do that and it is indeed working:

<?php
// graph-ql is installed via composer
require('../vendor/autoload.php');

use GraphQL\Language\Parser;
use GraphQL\Utils\BuildSchema;
use GraphQL\Utils\AST;
use GraphQL\GraphQL;

try {
    $cacheFilename = 'cached_schema.php';
    // caching, as recommended in the docs, is disabled for testing
    // if (!file_exists($cacheFilename)) {
        $document = Parser::parse(file_get_contents('./schema.graphql'));
        file_put_contents($cacheFilename, "<?php\nreturn " . var_export(AST::toArray($document), true) . ';');
    /*} else {
        $document = AST::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well
    }*/

    $typeConfigDecorator = function($typeConfig, $typeDefinitionNode) {
        // In the docs, this function is just empty, but I needed to return the $typeConfig, otherwise I got an error
        return $typeConfig;
    };
    $schema = BuildSchema::build($document, $typeConfigDecorator);

    $context = (object)array();

    // this has been taken from one of the examples provided in the repo
    $rawInput = file_get_contents('php://input');
    $input = json_decode($rawInput, true);
    $query = $input['query'];
    $variableValues = isset($input['variables']) ? $input['variables'] : null;
    $rootValue = ['prefix' => 'You said: '];
    $result = GraphQL::executeQuery($schema, $query, $rootValue, $context, $variableValues);
    $output = $result->toArray();
} catch (\Exception $e) {
    $output = [
        'error' => [
            'message' => $e->getMessage()
        ]
    ];
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($output);

This is what my schema.graphql file looks like:

schema {
    query: Query    
}

type Query {
    products: [Product!]!
}

type Product {
    id: ID!,
    type: ProductType
}

enum ProductType {
    HDRI,
    SEMISPHERICAL_HDRI,
    SOUND
}

I can query it for example with

query {
  __schema {types{name}}
}

and this will return the metadata as expected. But of course now I want to query for actual product data and get that from a database, and for that I'd need to define a resolver function.

The docs at http://webonyx.github.io/graphql-php/type-system/type-language/ state: "By default, such schema is created without any resolvers. We have to rely on default field resolver and root value in order to execute a query against this schema." - but there is no example for doing this.

How can I add resolver functions for each of the types/fields?


Solution

  • Here's what I ended up doing...

    $rootResolver = array(
        'emptyCart' => function($root, $args, $context, $info) {
            global $rootResolver;
            initSession();
            $_SESSION['CART']->clear();
            return $rootResolver['getCart']($root, $args, $context, $info);
        },
        'addCartProduct' => function($root, $args, $context, $info) {
            global $rootResolver;
    
            ...
    
            return $rootResolver['getCart']($root, $args, $context, $info);
        },
        'removeCartProduct' => function($root, $args, $context, $info) {
            global $rootResolver;
    
            ...
    
            return $rootResolver['getCart']($root, $args, $context, $info);
        },
        'getCart' => function($root, $args, $context, $info) {
            initSession();
            return array(
                'count' => $_SESSION['CART']->quantity(),
                'total' => $_SESSION['CART']->total(),
                'products' => $_SESSION['CART']->getProductData()
            );
        },
    

    and then in the config

    $config = ServerConfig::create()
        ->setSchema($schema)
        ->setRootValue($rootResolver)
        ->setContext($context)
        ->setDebug(DEBUG_MODE)
        ->setQueryBatching(true)
    ;
    
    $server = new StandardServer($config);
    

    It feels rather hack-ish to me, and I should probably outsource the resolvers into separate files, but it works... Still baffled that there are no simple examples for this task, maybe in an even better way than my solution...