Developed with love by KnpLabs Hire us for your project!
264

GraphQLBundle

by Youshido

Pure PHP implementation of GraphQL Server – Symfony Bundle

Symfony GraphQl Bundle

This is a bundle based on the pure PHP GraphQL Server implementation

This bundle provides you with:

  • Full compatibility with the RFC Specification for GraphQL
  • Agile object oriented structure to architect your GraphQL Schema
  • Intuitive Type system that allows you to build your project much faster and stay consistent
  • Built-in validation for the GraphQL Schema you develop
  • Well documented classes with a lot of examples
  • Automatically created endpoint /graphql to handle requests

There are simple demo application to demonstrate how we build our API, see GraphQLDemoApp.

Table of Contents

Installation

We assume you have composer, if you're not – install it from the official website.

If you need any help installing Symfony framework – here's the link http://symfony.com/doc/current/book/installation.html.

Shortcut to install Symfony: composer create-project symfony/framework-standard-edition my_project_name

Once you have your composer up and running – you're ready to install the GraphQL Bundle.

Go to your project folder and run:
sh
composer require youshido/graphql-bundle

Then enable bundle in your app/AppKernel.php
php
new Youshido\GraphQLBundle\GraphQLBundle(),

Add the routing reference to the app/config/routing.yml:
yaml
graphql:
resource: "@GraphQLBundle/Controller/"

or
yaml
graphql:
resource: "@GraphQLBundle/Resources/config/route.xml"

If you don't have a web server configured you can use a bundled version, simply run php bin/console server:run.

Let's check if you've done everything right so far – try to access url localhost:8000/graphql.

You should get a JSON response with the following error:
js
{"errors":[{"message":"Schema class does not exist"}]}

That's because there was no GraphQL Schema specified for the processor yet. You need to create a GraphQL Schema class and set it inside your app/config/config.yml file.

There is a way where you can use inline approach and do not create a Schema class, in order to do that you have to define your own GraphQL controller and use a ->setSchema method of the processor to set the Schema.

The fastest way to create a Schema class is to use a generator shipped with this bundle:
sh
php bin/console graphql:configure AppBundle

Here AppBundle is a name of the bundle where the class will be generated in.

You will be requested for a confirmation to create a class.

After you've added parameters to the config file, try to access the following link in the browser – http://localhost:8000/graphql?query={hello(name:World)}

Alternatively, you can execute the same request using CURL client in your console

curl http://localhost:8000/graphql --data "query={ hello(name: \"World\") }"

Successful response from a test Schema will be displayed:
js
{"data":{"hello":"world!"}}

That means you have GraphQL Bundle for the Symfony Framework configured and now can architect your GraphQL Schema:

Next step would be to link assets for GraphiQL Explorer by executing:
sh
php bin/console assets:install --symlink

Now you can access it at http://localhost:8000/graphql/explorer

Symfony features

Class AbstractContainerAwareField:

AbstractContainerAwareField class used for auto passing container to field, add ability to use container in resolve function:
```php
class RootDirField extends AbstractContainerAwareField
{

/**
 * @inheritdoc
 */
public function getType()
{
    return new StringType();
}

/**
 * @inheritdoc
 */
public function resolve($value, array $args, ResolveInfo $info)
{
    return $this->container->getParameter('kernel.root_dir');
}

/**
 * @inheritdoc
 */
public function getName()
{
    return 'rootDir';
}

### Service method as callable:
Ability to pass service method as resolve callable:
```php
$config->addField(new Field([
    'name'    => 'cacheDir',
    'type'    => new StringType(),
    'resolve' => ['@resolve_service', 'getCacheDir']
]))

Events:

You can use the Symfony Event Dispatcher to get control over specific events which happen when resolving graphql queries.

namespace ...\...\..;

use Youshido\GraphQL\Event\ResolveEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class MyGraphQLResolveEventSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            'graphql.pre_resolve'  => 'onPreResolve',
            'graphql.post_resolve' => 'onPostResolve'
        ];
    }

    public function onPreResolve(ResolveEvent $event)
    {
        //$event->getFields / $event->getAstFields()..
    }

    public function onPostResolve(ResolveEvent $event)
    {
        //$event->getFields / $event->getAstFields()..
    }
}

Configuration

Now configure you subscriber so events will be caught. This can be done in Symfony by either XML, Yaml or PHP.

<service id="my_own_bundle.event_subscriber.my_graphql_resolve_event_subscriber" class="...\...\...\MyGraphQLResolveEventSubscriber">
    <tag name="graphql.event_subscriber" />
</service>

Security:

Bundle provides two ways to guard your application: using black/white operation list or using security voter.

Black/white list

Used to guard some root operations. To enable it you need to write following in your config.yml file:
```yaml
graphql:

#...

security:
black_list: ['hello'] # or white_list: ['hello']

#### Using security voter:
Used to guard any field resolve and support two types of guards: root operation and any other field resolving (including internal fields, scalar type fields, root operations). To guard root operation with your specified logic you need to enable it in configuration and use  `SecurityManagerInterface::RESOLVE_ROOT_OPERATION_ATTRIBUTE` attribute. The same things need to do to enable field guard, but in this case use `SecurityManagerInterface::RESOLVE_FIELD_ATTRIBUTE` attribute.
[Official documentation](http://symfony.com/doc/current/security/voters.html) about voters.

> Note: Enabling field security lead to a significant reduction in performance

Config example:
```yaml
graphql:
    security:
        guard:
            field: true # for any field security
            operation: true # for root level security

Voter example (add in to your services.yml file with tag security.voter):
```php
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Youshido\GraphQL\Execution\ResolveInfo;
use Youshido\GraphQLBundle\Security\Manager\SecurityManagerInterface;

class GraphQLVoter extends Voter
{

/**
 * @inheritdoc
 */
protected function supports($attribute, $subject)
{
    return in_array($attribute, [SecurityManagerInterface::RESOLVE_FIELD_ATTRIBUTE, SecurityManagerInterface::RESOLVE_ROOT_OPERATION_ATTRIBUTE]);
}

/**
 * @inheritdoc
 */
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
    // your own validation logic here

    if (SecurityManagerInterface::RESOLVE_FIELD_ATTRIBUTE == $attribute) {
        /** @var $subject ResolveInfo */
        if ($subject->getField()->getName() == 'hello') {
            return false;
        }

        return true;
    } elseif (SecurityManagerInterface::RESOLVE_ROOT_OPERATION_ATTRIBUTE == $attribute) {
        /** @var $subject Query */
        if ($subject->getName() == '__schema') {
            return true;
        }
    }
}

}
```

GraphiQL extension:

To run graphiql extension just try to access to http://your_domain/graphql/explorer

Documentation

All detailed documentation is available on the main GraphQL repository – http://github.com/youshido/graphql/.

graphql:
schema_class: ~
schema_service: ~
max_complexity: ~
logger: ~
security:
guard:
operation: false
field: false
white_list: []
black_list: []
response:
json_pretty: true
headers:
name: ~
value: ~
  • fixes after merge
    By portey, 7 months ago
  • Merge pull request #69 from i-melnichenko/remove-sensioframeworkextrabundle
    By web-flow, 7 months ago
  • Merge pull request #73 from bugaga/sm4-support
    By web-flow, 7 months ago
  • Merge pull request #72 from symm/fix-command-autoregistration
    By web-flow, 7 months ago
  • sm4 support
    By Artem Bilenskiy, 7 months ago
  • Register configure command in container.
    By symm, 7 months ago
  • Merge pull request #70 from justinlevi/master
    By web-flow, 8 months ago
  • Minor update to installation instructions
    By web-flow, 8 months ago
  • code style
    By , 9 months ago
  • Merge pull request #67 from melnikod/remove-sensio_framework_extra_bundle
    By web-flow, 9 months ago
  • Merge pull request #52 from LiFeAiR/CSRF-support
    By web-flow, 11 months ago
  • Merge pull request #65 from symm/config-test-coverage
    By web-flow, 11 months ago
  • remove SensioFrameworkExtraBundle; review
    By i-melnichenko, 11 months ago
  • remove SensioFrameworkExtraBundle; fix doc
    By i-melnichenko, 11 months ago
  • fix routing names
    By i-melnichenko, 11 months ago
  • remove SensioFrameworkExtraBundle
    By i-melnichenko, 11 months ago
  • Merge pull request #48 from MLoureiro/fix/allow-gpraphql-schema-to-be-initialized-through-compiler-pass
    By web-flow, 11 months ago
  • Add test coverage for extension config
    By symm, 11 months ago
  • Merge pull request #53 from iainmckay/allow-service-resolvers-on-custom-fields
    By web-flow, 11 months ago
  • Merge pull request #51 from JeremyGreaux/patch-1
    By web-flow, 11 months ago
  • Merge pull request #63 from iainmckay/allow-resolve-listeners-to-override-result
    By web-flow, 11 months ago
  • Allows resolve event listeners to override or manipulate the resolved result
    By iainmckay, 1 year ago
  • Fixes broken container aware field
    By iainmckay, 1 year ago
  • Enables service based resolvers on custom fields
    By iainmckay, 1 year ago
  • add CSRF cookie support
    By web-flow, 1 year ago
  • Correct extension name "graph_ql" to "graphql"
    By , 1 year ago
  • Merge pull request #50 from Youshido/m-naw-bug/application/graphql-content-type
    By web-flow, 1 year ago
  • Pull request 28: Refactored code
    By portey, 1 year ago
  • Merge pull request #29 from MGDSoft/patch-1
    By web-flow, 1 year ago
  • Merge pull request #45 from dkreuer/patch-1
    By web-flow, 1 year ago