## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require bastsys/graphql-bundle
Add the bundle to config/bundles.php:
return [
// ...
Bastsys\GraphQLBundle\BastsysGraphQLBundle::class => ['all' => true],
];
First Endpoint:
The bundle auto-registers /graphql endpoint. Test it immediately with a query like:
query {
__schema {
types {
name
}
}
}
(Send via Postman/cURL with Content-Type: application/json.)
Define a Basic Type:
Create a resolver class (e.g., src/GraphQL/Resolver/Query.php):
namespace App\GraphQL\Resolver;
use Bastsys\GraphQLBundle\Resolver\AbstractResolver;
use Bastsys\GraphQLBundle\Type\Type;
class Query extends AbstractResolver
{
public function hello(): string
{
return 'Hello, GraphQL!';
}
}
Register it in config/packages/bastsys_graphql.yaml:
bastsys_graphql:
resolvers:
query: App\GraphQL\Resolver\Query
Query the Resolver:
query {
hello
}
Query/Mutation Structure:
Organize resolvers by operation type (e.g., Query, Mutation, Subscription). Example:
// src/GraphQL/Resolver/Mutation.php
class Mutation extends AbstractResolver
{
public function createUser(string $name): array
{
// Logic here
return ['name' => $name, 'id' => 1];
}
}
Register in bastsys_graphql.yaml:
bastsys_graphql:
resolvers:
mutation: App\GraphQL\Resolver\Mutation
Nested Resolvers:
Use AbstractContainerAwareField for dependency injection:
use Bastsys\GraphQLBundle\Field\AbstractContainerAwareField;
class UserField extends AbstractContainerAwareField
{
public function resolve($root, array $args)
{
return $this->container->get('user.repository')->find($args['id']);
}
}
Register the field in your resolver’s buildSchema() method.
Custom Types:
Define types via PHP classes (e.g., src/GraphQL/Type/UserType.php):
use Bastsys\GraphQLBundle\Type\ObjectType;
class UserType extends ObjectType
{
public function __construct()
{
$this->addField('id', 'ID');
$this->addField('name', 'String');
}
}
Use in resolvers:
public function getUser(): UserType
{
return new UserType(['id' => 1, 'name' => 'John']);
}
Input Types:
For mutations, create input types (e.g., UserInputType):
use Bastsys\GraphQLBundle\Type\InputType;
class UserInputType extends InputType
{
public function __construct()
{
$this->addField('name', 'String');
}
}
Use in mutations:
public function createUser(UserInputType $input): UserType
{
// ...
}
Inject Services:
Use AbstractContainerAwareField or Symfony’s DI:
class Query extends AbstractResolver
{
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function getUsers(): array
{
return $this->userService->all();
}
}
Service Methods as Callables:
Register service methods directly in bastsys_graphql.yaml:
bastsys_graphql:
resolvers:
query:
getUsers: ['@user.service', 'all']
Authentication: Use Symfony’s security component in resolvers:
public function protectedData(): string
{
if (!$this->container->get('security.token_storage')->getToken()) {
throw new \Exception('Unauthorized');
}
return 'Secret data';
}
Or via middleware (extend GraphQLMiddleware).
Authorization: Implement custom logic in resolvers:
public function deleteUser(int $id): bool
{
$user = $this->container->get('user.repository')->find($id);
if (!$this->container->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
throw new \Exception('Forbidden');
}
return $user->delete();
}
Dynamic Schema: Build schemas programmatically in resolvers:
public function buildSchema()
{
$schema = $this->schemaFactory->createSchema();
$schema->addType(new UserType());
$schema->addQuery($this->createQueryType());
return $schema;
}
Fragments and Interfaces: Use PHP interfaces for shared fields:
interface NodeInterface {
public function getId();
}
class UserType extends ObjectType implements NodeInterface { ... }
Circular Dependencies: Avoid circular references in resolvers/types. Use lazy-loading or interfaces to break cycles.
Type Mismatches: Ensure resolver return types match GraphQL type definitions. Example:
// ❌ Fails: Returns `array` but expects `UserType`
public function getUser(): array { ... }
// ✅ Works
public function getUser(): UserType { return new UserType(...); }
Case Sensitivity:
GraphQL field names are case-sensitive. Match resolver method names exactly (e.g., getUser vs getuser).
Schema Validation:
Use the /graphql endpoint with introspection to validate your schema:
query {
__schema {
types {
name
fields {
name
type {
name
}
}
}
}
}
Error Handling: Catch exceptions in resolvers and return GraphQL errors:
public function riskyOperation(): string
{
try {
// ...
} catch (\Exception $e) {
throw new \Bastsys\GraphQLBundle\Exception\GraphQLException(
$e->getMessage(),
['code' => $e->getCode()]
);
}
}
Logging:
Enable debug mode in bastsys_graphql.yaml:
bastsys_graphql:
debug: true
Logs appear in Symfony’s profiler or var/log/dev.log.
Resolver Priority:
Resolvers are loaded in alphabetical order. Use explicit keys in bastsys_graphql.yaml to control order:
bastsys_graphql:
resolvers:
query:
getUsers: App\GraphQL\Resolver\Query::getUsers
listUsers: App\GraphQL\Resolver\Query::listUsers
Caching:
Disable caching during development (debug: true). Enable in production:
bastsys_graphql:
cache:
enabled: true
adapter: apcu
Introspection: Disable introspection in production for security:
bastsys_graphql:
introspection:
enabled: false
Custom Directives: Extend the bundle’s directive system:
use Bastsys\GraphQLBundle\Directive\AbstractDirective;
class DeprecatedDirective extends AbstractDirective
{
public function validate($value, array $args, $context)
{
if (isset($args['reason'])) {
return true;
}
throw new \Exception('Deprecated without reason');
}
}
Register in bastsys_graphql.yaml:
bastsys_graphql:
directives:
deprecated: App\GraphQL\Directive\DeprecatedDirective
Middleware: Add custom middleware (e.g., for logging or auth):
use Bastsys\GraphQLBundle\Middleware\GraphQLMiddlewareInterface;
class LoggingMiddleware implements GraphQLMiddlewareInterface
{
public function handle($request, \Closure $next)
{
$start = microtime(true);
$response = $next($request
How can I help you explore Laravel packages today?