Installation
composer require api-platform/graphql
Ensure your project uses API Platform (api-platform/core) and Symfony Flex (or manually configure autoloading).
Enable the Bundle
Add to config/bundles.php:
return [
// ...
ApiPlatform\GraphQL\Bundle\GraphQLBundle::class => ['all' => true],
];
First Query
Configure GraphQL endpoint in config/packages/api_platform.yaml:
api_platform:
formats:
jsonld: ['application/ld+json']
json: ['application/json']
html: ['text/html']
graphql: ['application/graphql']
Test with a simple query at /graphql:
query {
users {
id
name
}
}
Key Files to Review
config/packages/api_platform.yaml (GraphQL settings)src/Entity/ (Your API resources)src/GraphQL/ (Custom resolvers, if needed)@ApiResource).ApiPlatform\GraphQL\Generator\SchemaGenerator or using decorators.query {
users { id name }
posts { title content }
}
?filter[where][name][contains]=John → GraphQL equivalent):
query {
users(filter: { name: { contains: "John" } }) { id name }
}
create<Entity>, update<Entity>, delete<Entity> mutations:
mutation {
createUser(input: { name: "Alice", email: "alice@example.com" }) {
id name
}
}
@GraphQL\Query/@GraphQL\Mutation attributes.query {
posts {
title
author { name }
}
}
first, last, after, before arguments:
query {
users(first: 10) { id name }
}
src/GraphQL/Query/UserResolver) and tag it:
#[Query]
class UserResolver {
#[Resolve(name: "User")]
public function resolve(UserInterface $user): array {
return [
'id' => $user->getId(),
'customField' => $user->getCustomField(),
];
}
}
UserRepository, Serializer).@Groups:
#[ApiResource(
normalizationContext: ['groups' => ['user:read']]
)]
class User { ... }
query {
users { id name } # Only fields in 'user:read' group
}
@IsGranted):
#[Query]
class AdminQuery {
#[Resolve(name: "adminDashboard")]
#[IsGranted("ROLE_ADMIN")]
public function dashboard(): array { ... }
}
$context in resolvers:
public function __invoke($root, array $args, $context) {
$user = $context['security']->getUser();
}
config/packages/api_platform.yaml:
api_platform_graphql:
schema_cache_enabled: true
schema_cache_ttl: 3600 # 1 hour
php bin/console cache:clear after schema changes.#[ApiResource(denormalizationContext: ['groups' => ['user:write']])] and eager-load relationships:
query {
users { id posts { title } } # Loads posts eagerly if configured
}
DateTime, Upload).config/packages/api_platform_graphql.yaml:
api_platform_graphql:
custom_scalars:
DateTime: 'App\GraphQL\Scalar\DateTimeScalar'
@Assert constraints in entities or custom resolvers:
use Symfony\Component\Validator\Constraints as Assert;
#[Assert\NotBlank]
private ?string $email;
Errors appear in GraphQL response under errors.query {
users(first: 20) { id name }
}
query {
users { id } # Only fetch IDs
}
/graphql for interactive testing.var/log/dev.log for schema generation errors.api_platform.graphql.schema.generated to debug schema issues:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use ApiPlatform\GraphQL\Event\SchemaGeneratedEvent;
class SchemaSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [SchemaGeneratedEvent::NAME => 'onSchemaGenerated'];
}
public function onSchemaGenerated(SchemaGeneratedEvent $event) {
// Dump schema for debugging
file_put_contents('schema.graphql', $event->getSchema()->__toString());
}
}
src/GraphQL/Type/ directory and use @GraphQL\Type:
#[Type]
class CustomType {
#[Field]
public function field(): string { return "value"; }
}
#[UnionType(name: "Content")]
class ContentUnion { ... }
jsonld format).composer update api-platform/core api-platform/graphql
use ApiPlatform\GraphQL\Generator\SchemaGenerator;
$schemaGenerator = new SchemaGenerator($entityManager);
$schema = $schemaGenerator->generateSchema();
GraphQLClient (e.g., webonyx/graphql-php):
$client = new GraphQLClient('http://localhost/graphql');
$result = $client->query('{ users { id } }');
User → Post → User).
Fix: Use @MaxDepth or @ApiResource(iri="...") to break cycles.users vs Users).null for missing fields; use @GraphQL\Deprecated to mark obsolete fields.How can I help you explore Laravel packages today?