GraphQL
MonkeysLegion GraphQL adds a full GraphQL stack to the MonkeysLegion framework:
What | How |
|---|---|
HTTP endpoint | POST /graphql (also GET /graphql?query=…) |
Type system | Pure PHP 8 attributes (#[Type], #[Query], #[Mutation], #[Subscription]) |
Dev tools | GraphiQL playground at /graphiql (dev only) |
Real-time | WebSocket server on ws://<host>:6001 (subscriptions) |
DI / PSR-15 | Services are auto-bound through MonkeysLegion’s provider mechanism |
Installation
composer require monkeyscloud/monkeyslegion-graphqlThe package injects itself into
composer.json → extra.monkeyslegion.providers, so your bootstrap
automatically calls MonkeysLegion\GraphQL\GraphQL::register().
Quick Start
// app/GraphQL/Types/Post.php
namespace App\GraphQL\Types;
use MonkeysLegion\GraphQL\Attribute\Type;
use GraphQL\Type\Definition\{ObjectType, Type as GQL};
#[Type]
final class Post extends ObjectType
{
public function __construct()
{
parent::__construct([
'name' => 'Post',
'fields' => [
'id' => GQL::nonNull(GQL::id()),
'title' => GQL::string(),
'body' => GQL::string(),
],
]);
}
}// app/GraphQL/Query/PostQuery.php
namespace App\GraphQL\Query;
use MonkeysLegion\GraphQL\Attribute\Query;
use App\Repository\PostRepository;
#[Query(name: 'posts')]
final class PostQuery
{
public function __construct(private PostRepository $repo) {}
public function __invoke(): array
{
return $this->repo->findAll();
}
}GET /graphiql → run:
{
posts { id title }
}Defining Schema Elements
Attribute | Extends / implements | Expected return value |
|---|---|---|
#[Type] | GraphQL\Type\Definition\ObjectType | n/a |
#[Query] | callable or ObjectType | Resolver result |
#[Mutation] | callable or ObjectType | Resolver result |
#[Subscription] | callable or ObjectType | Async iterator / generator |
Example Mutation
#[Mutation(name: 'createPost')]
final class CreatePost
{
public function __construct(private PostRepository $repo) {}
public function __invoke(null $_, array $args): int
{
return $this->repo->insert($args['title'], $args['body']);
}
}Subscriptions
Start the WebSocket server (CLI, Supervisor, or systemd):
use MonkeysLegion\GraphQL\WebSocket\SubscriptionServer;
SubscriptionServer::run(
$container->get(SubscriptionManager::class),
$container->get(PubSubInterface::class), // default InMemoryPubSub
);Define a subscription type:
#[Subscription('counter')]
class CounterSub extends ObjectType
{
public function __construct(PubSubInterface $ps)
{
parent::__construct([
'name' => 'CounterSub',
'fields' => [ 'count' => ['type' => GQL::int()] ],
'subscribe' => fn() => $ps->subscribe('counter', fn($v)=>['count'=>$v]),
'resolve' => fn($root) => $root,
]);
}
}Publish events anywhere in your app:
$pubsub->publish('counter', $value++);Client:
const ws = new WebSocket('ws://localhost:6001');
ws.onopen = () => ws.send(JSON.stringify({
query: 'subscription { counter { count } }'
}));
ws.onmessage = e => console.log(JSON.parse(e.data));Switching to Redis Pub/Sub
Swap the entry for PubSubInterface::class in your DI config to a Redis-backed implementation (community driver).
Key | Default | Description |
|---|---|---|
graphql.playground | true in dev | Expose /graphiql |
graphql.ws.port | 6001 | WebSocket port |
graphql.ws.host | 0.0.0.0 | Bind address |
graphql.pubsub | in_memory | in_memory or redis |
Add these keys to config/graphql.mlc:
playground = env("GQL_PLAYGROUND", true)
ws.port = 6001
ws.host = "0.0.0.0"
pubsub = "in_memory"MlcConfig is loaded automatically by the provider.
CLI Helpers
php vendor/bin/ml graphql:subscriptions # start WS server
php vendor/bin/ml graphql:schema:print # dump SDLTroubleshooting
Symptom | Fix |
|---|---|
404 /graphiql | Set APP_ENV=dev or graphql.playground=true. |
“Undefined class Loop” | You’re on React 0.4: use React\EventLoop\Factory::create() not Loop::get(). |
WebSocket closes immediately | Check browser console; ensure server port & scheme match. |
Subscription resolves once then stops | Remember to call the unsubscribe callback inside your generator. |
Roadmap
v0.3 – DataLoader batching, per-request cache
v0.4 – Relay cursor-based pagination helpers
v1.0 – Federation helpers, Apollo Gateway integration
Contributing
git clone & composer install
Run tests: vendor/bin/phpunit – must stay green.
Follow PSR-12, add doc-blocks & tests.
Open PRs against main.
MIT license – happy hacking! 🐒🚀