reydajp / cake-graphql
GraphQL endpoint plugin for CakePHP 5 using GraphQLite and Webonyx GraphQL PHP.
Package info
github.com/reydajp/cakephp-graphql-plugin
Type:cakephp-plugin
pkg:composer/reydajp/cake-graphql
Requires
- php: >=8.3
- cakephp/cakephp: ^5.0
- thecodingmachine/graphqlite: ^8.3
- webonyx/graphql-php: ^15.32
Requires (Dev)
- phpunit/phpunit: ^12.0
Conflicts
- thecodingmachine/safe: <3.4
This package is auto-updated.
Last update: 2026-07-26 15:18:16 UTC
README
CakeGraphQL - GraphQL plugin for CakePHP 5
CakeGraphQL is a CakePHP 5 plugin for GraphQL endpoint routing, endpoint-level authentication, engine selection, and GraphQLite integration.
The plugin owns the HTTP endpoint and GraphQL engine wiring. The host application owns resolver classes, entity/type annotations, authentication provider setup, field-level authorization, and business logic.
Requirements
- PHP 8.3 or newer
- CakePHP 5
- GraphQLite 8
- Webonyx GraphQL PHP 15
Installation
composer require reydajp/cake-graphql
Load the plugin in the host application:
// src/Application.php public function bootstrap(): void { parent::bootstrap(); $this->addPlugin('CakeGraphQL'); }
Configuration
Configure the plugin with the Graphql key:
// config/app_local.php or config/app.php 'Graphql' => [ 'path' => '/api/graphql', 'engine' => 'Graphqlite', 'authenticated' => true, 'engines' => [ 'Graphqlite' => [ 'queries' => [ App\Graphql\UsersQuery::class, ], 'types' => [ App\Model\Entity\User::class, ], 'cache' => 'default', 'debug' => false, 'maxDepth' => 10, 'maxComplexity' => 200, ], ], ],
The plugin registers the configured route and attaches route-specific GraphQL middleware. CakePHP routing middleware must run as usual in the host application. maxDepth and maxComplexity reject overly nested or expensive GraphQL operations before resolver execution.
See docs/configuration.md for the full configuration contract.
Resolver Example
<?php declare(strict_types=1); namespace App\Graphql; use Cake\ORM\Locator\LocatorAwareTrait; use TheCodingMachine\GraphQLite\Annotations\Query; final class UsersQuery { use LocatorAwareTrait; #[Query] public function users(int $limit = 50): array { $limit = max(1, min($limit, 100)); return $this->fetchTable('Users')->find()->limit($limit)->all()->toList(); } }
Register resolver classes explicitly in Graphql.engines.Graphqlite.queries. CakeGraphQL does not scan broad application namespaces by default.
See docs/graphqlite.md for CakePHP examples using GraphQLite #[Query], #[Type], and #[Field] attributes.
Error Responses
CakeGraphQL returns normal GraphQL partial responses for resolver and field errors after execution starts: HTTP 200, partial data, and an errors entry with the field path. Cake HTTP exceptions thrown by resolvers expose their client-safe message, for example User not found.
Endpoint-level authentication still happens before GraphQL execution. When authenticated is true and the request has no Cake identity, the endpoint returns HTTP 401. Resolver-level authentication errors from GraphQLite attributes such as #[Logged] are GraphQL execution errors and return HTTP 200.
Bake Command
Generate a collection query resolver:
bin/cake bake graphql query Users
Generate a single-record query resolver:
bin/cake bake graphql query Users --single
Generate into a custom namespace:
bin/cake bake graphql query Users --namespace App\\Api\\Graphql
By default, the command updates Graphql.engines.Graphqlite.queries in config/app_local.php or config/app.php. Use --no-config to skip that update.
See docs/bake.md for details.
Authentication
When authenticated is true, CakeGraphQL rejects requests before GraphQL execution if the request has no identity attribute. This relies on the host application's Cake Authentication middleware running before the GraphQL route middleware.
CakeGraphQL bridges Cake Authentication's request identity into GraphQLite's authentication service. GraphQLite resolvers can inject the current Cake user with #[InjectUser]:
use App\Model\Entity\User; use TheCodingMachine\GraphQLite\Annotations\InjectUser; use TheCodingMachine\GraphQLite\Annotations\Query; final class UsersQuery { #[Query] public function me(#[InjectUser] ?User $user): ?User { return $user; } }
If the injected parameter is not nullable, GraphQLite requires a logged-in user for that field. #[Logged] also uses the bridged Cake identity.
The bridge reads Cake's request identity attribute. AuthenticationComponent remains controller-only and is not available inside resolver classes.
Field-level authorization is intentionally engine-specific. GraphQLite attributes such as #[Right] or #[Security] require GraphQLite authorization services; CakeGraphQL does not currently bridge Cake Authorization into those services.
See docs/graphqlite.md for examples and the current integration boundary.
Commands
composer test composer validate --strict find src tests -name '*.php' -exec php -l {} \;
License
MIT. See LICENSE.