linkfast / exengine-graphql
GraphQL for the ExEngine microframework: schema-first, precompiled schema, persisted queries.
Package info
gitlab.com/linkfast/oss/exengine-extensions/exengine-graphql
Type:exengine-extension
pkg:composer/linkfast/exengine-graphql
Requires
- php: >=8.1
- linkfast/exengine: ^1.3.0-a3
- webonyx/graphql-php: ^15.0
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.0 || ^12.0 || ^13.0
Suggests
- ext-apcu: Lets automatic persisted queries (APQ) be shared by the requests of a PHP-FPM server.
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-10-14 05:53:40 UTC
README
GraphQL for the ExEngine microframework, built on webonyx/graphql-php. The schema comes first and is precompiled during development. For production there are persisted queries and query limits.
© LinkFast S.A. (https://linkfast.io) · MIT License
In development (pre-releases
1.0.0-aN).
Requirements
- PHP 8.1 or higher
- ExEngine 1.3.0-a3 or higher (needed for explicit routes)
- Optional:
ext-apcu, so that PHP-FPM processes share automatic persisted queries
Installation
exen extension:add linkfast/exengine-graphql:^1.0.0-a1
You can also run composer require linkfast/exengine-graphql:^1.0.0-a1. ExEngine activates the extension at boot.
Then generate the code of your schema with exen (1.0.0-a6 or higher), which reads it with this package's webonyx/graphql-php:
exen contract:add schema.graphql --name shop # or: exen new shop --api schema.graphql
exen contract:add schema.graphql --name shop --operations contracts/shop # with trusted documents
exen writes the models, one interface per type you resolve (QueryApi, MutationApi, ...), the
SchemaDefinition with the precompiled schema, the Extension that registers it, and your resolvers
(src/Shop/QueryResolver.php), once. Run exen generate after editing the schema. See the
exen README for the details and for
generated GraphQL clients.
How it works
The extension serves the application's schema at graphql.path (default /graphql):
GETaccepts queries only.POSTaccepts any operation, sent either as a JSON body (query,variables,operationName,extensions) or as the operation text withContent-Type: application/graphql.
The application registers its schema as a SchemaDefinition, which exen generate writes:
ast()returns the SDL already parsed into an array during development, so nothing is parsed at runtime. Each process builds the schema once, and a RoadRunner worker reuses it for every request.resolvers()lists, for each GraphQL type, the application class that resolves it and the fields that class handles: every field of the root types, and the fields with arguments or marked@resolve. That class is created through dependency injection once per request. Any other field is read from the parent value, as a public property or an array key.enums()maps GraphQL enums to PHP backed enums. Resolvers receive and return those enums.types()maps GraphQL object types to their PHP classes, which is how interfaces and unions are resolved.documents()lists the trusted documents as sha256 => operation (from the operation documents exen validated).
To report an error the client should see, a resolver throws ExEngine\GraphQL\UserError, optionally with a code
that appears in extensions.code. Any other exception is reported only as "Internal server error".
Configuration
| Key | Default | Description |
|---|---|---|
graphql.path | /graphql | Path of the endpoint |
graphql.introspection | true | Allow introspection (turn it off in production) |
graphql.max-depth | 15 | Maximum query depth; 0 for no limit |
graphql.max-complexity | 0 | Maximum query complexity; 0 for no limit |
graphql.trusted-documents | false | Run only the trusted documents, sent by their sha256 (documentId) |
graphql.apq | off | Automatic persisted queries: off, memory (per process) or apcu |
graphql.debug | false | Include exception messages and traces in errors (development only) |
Development
composer install
vendor/bin/phpunit
License
MIT, see LICENSE.