graphql-attribute-schema

πŸš€ Getting Started

βœ… Requirements

GraphQL Attribute Schema is a standalone library, but it depends on a few essential packages:

πŸ“¦ Installation

Install the package via Composer:

composer require jerowork/graphql-attribute-schema

πŸ”§ Integrating with webonyx/graphql-php

To generate a GraphQL Schema for webonyx/graphql-php, this library provides a SchemaBuilder.
It requires an Abstract Syntax Tree (AST), which is created using the Parser.

You can quickly set up both using the provided factories:

use GraphQL\Server\StandardServer;
use GraphQL\Server\ServerConfig;
use Jerowork\GraphqlAttributeSchema\ParserFactory;
use Jerowork\GraphqlAttributeSchema\SchemaBuilderFactory;

// 1. Set up your PSR-11 compatible container
$container = new YourPsr11Container();

// 2. Create an AST from your GraphQL classes
$ast = (new ParserFactory())->create()->parse(__DIR__ . '/Path/To/GraphQL');

// 3. Build the schema from the AST
$schema = (new SchemaBuilderFactory())->create($container)->build($ast);

// 4. Add the schema to Webonyx StandardServer
$server = new StandardServer(ServerConfig::create([
    'schema' => $schema,
]));

πŸ“Œ This library does not create a GraphQL server for you.

To learn how to set up a server, check the webonyx documentation.

⚑ Example: GraphQL Server with Symfony

For a quick start, here’s an example of a GraphQL server in Symfony.
(Requires symfony/psr-http-message-bridge and a PSR-7 implementation like guzzlehttp/psr7.)

This example omits error handling for simplicity.

use GraphQL\Server\StandardServer;
use GraphQL\Server\ServerConfig;
use Jerowork\GraphqlAttributeSchema\ParserFactory;
use Jerowork\GraphqlAttributeSchema\SchemaBuilderFactory;
use Psr\Container\ContainerInterface;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;

#[AsController]
final readonly class GraphQLServerController
{
    public function __construct(
        private ContainerInterface $container,
        private HttpMessageFactoryInterface $httpMessageFactory,
        private ParserFactory $parserFactory,
        private SchemaBuilderFactory $schemaBuilderFactory,
    ) {}

    #[Route('/graphql', name: 'graphql.server', methods: Request::METHOD_POST)]
    public function __invoke(Request $request): Response
    {
        // 1. Parse GraphQL schema
        $ast = $this->parserFactory->create()->parse(__DIR__ . '/Path/To/GraphQL');
        $schema = $this->schemaBuilderFactory->create($this->container)->build($ast);
        
        // 2. Create GraphQL server
        $server = new StandardServer(ServerConfig::create([
            'schema' => $schema,
        ]));
        
        // 3. Handle request
        $result = $server->executePsrRequest(
            $this->httpMessageFactory
                ->createRequest($request)
                ->withParsedBody(json_decode($request->getContent(), true, flags: JSON_THROW_ON_ERROR))
        );

        // 4. Handle batch requests
        if (is_array($result)) {
            return new JsonResponse(array_map(fn($res) => $res->toArray(), $result));        
        }
        
        // 5. Return response
        return new JsonResponse($result->toArray());
    }
}

🏎️ Caching for Performance

Parsing GraphQL classes and attributes can be expensive because it involves reflection.
To improve performance, cache the AST (Abstract Syntax Tree) using serialization.

Storing AST in Cache

use Jerowork\GraphqlAttributeSchema\ParserFactory;

// 1. Generate AST
$ast = (new ParserFactory())->create()->parse(__DIR__ . '/Path/To/GraphQL');

// 2. Store in cache
$someCache->set('graphql-attribute-schema.ast', json_encode($ast->toArray(), JSON_THROW_ON_ERROR));

Retrieving AST from Cache

use Jerowork\GraphqlAttributeSchema\SchemaBuilderFactory;
use Jerowork\GraphqlAttributeSchema\ParserFactory;
use Jerowork\GraphqlAttributeSchema\Ast;

// 1. Retrieve from cache
$astArray = json_decode($someCache->get('graphql-attribute-schema.ast'), true, flags: JSON_THROW_ON_ERROR);
$ast = Ast::fromArray($astArray);

// 2. Build schema
$schema = (new SchemaBuilderFactory())->create($container)->build($ast);