webonyx / graphql-php

PHP implementation of the GraphQL specification based on the reference implementation in JavaScript
https://webonyx.github.io/graphql-php
MIT License
4.65k stars 564 forks source link

Example using Zend Expressive #120

Closed benjamingb closed 7 years ago

benjamingb commented 7 years ago

Do you know of an example that works with Zend Expressive? He tried, but it works

vladar commented 7 years ago

None that I am aware of

vladar commented 7 years ago

As of version 0.10.0 there is a PSR-7 compatible standard server. It should be possible to use it as is with Zend Expressive.

PowerKiKi commented 6 years ago

FYI, this is the integration I came up with. It could be cleaner, but at least it is simple. The middleware itself looks like:

<?php

declare(strict_types=1);

namespace Application\Action;

use Application\Api\Schema;
use GraphQL\Doctrine\DefaultFieldResolver;
use GraphQL\GraphQL;
use GraphQL\Server\StandardServer;
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\JsonResponse;

class GraphQLAction implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, DelegateInterface $delegate)
    {
        GraphQL::setDefaultFieldResolver(new DefaultFieldResolver());

        $schema = new Schema();
        $server = new StandardServer([
            'schema' => $schema,
            'queryBatching' => true,
            'debug' => true,
        ]);

        $parsedBody = json_decode($request->getBody()->getContents(), true);
        $request = $request->withParsedBody($parsedBody);
        $response = $server->executePsrRequest($request);

        return new JsonResponse($response);
    }
}

Configure it in config/autoload/dependencies.global.php:

return [
    'dependencies' => [
        'invokables' => [
            GraphQLAction::class => GraphQLAction::class,
        ],
    ],
];

And declare a route in config/routes.php:

$app->post('/graphql', Application\Action\GraphQLAction::class, 'graphql');
vladar commented 6 years ago

@PowerKiKi You don't need following lines:

$parsedBody = json_decode($request->getBody()->getContents(), true);
$request = $request->withParsedBody($parsedBody);

They seem redundant as the server should already do it (if Content-Type header in the request is application/json).

Following should work as is (if something doesn't work, then it is probably a bug):

public function process(ServerRequestInterface $request, DelegateInterface $delegate)
{
    $schema = new Schema();
    $server = new StandardServer([
        'schema' => $schema,
        'queryBatching' => true,
        'debug' => true,
        'fieldResolver' => new DefaultFieldResolver()
    ]);
    $response = $server->executePsrRequest($request);
    return new JsonResponse($response);
}

Also, there is complementary project https://github.com/phps-cans/psr7-middleware-graphql

PowerKiKi commented 6 years ago

Thanks for mentioning psr7-middleware-graphql, I wasn't aware of it.

The parsing of JSON is necessary in my case, otherwise parsedBody is empty and the server will fail to decode json from non-parsed body. I was surprised by this behavior as I was expecting it would work out of the box as you described. Would you want me to open an issue for that ?

vladar commented 6 years ago

If parsedBody is empty, then it is a bug. Will appreciate if you open an issue for it. But are you sure Content-Type header is set properly to application/json in your case?