To start defining your schema, you will need to write plain php classes in the directory specified
in the configuration file for this schema (resource_directories
)
The classes should contain only public attributes or have a public getter for any protected/private attribute.
During schema generation, the classes will be scanned and the attributes they contain will be used to generate the schema.
If you want to expose your class as a resource, you will need to add the ApiResource
attribute to it.
ApiResources are used to expose queries, mutations or subscriptions to the dedicated Query/Mutation/Subscription types.
They also follow the relay specification for Node types (https://relay.dev/docs/guides/graphql-server-specification/).
Having an ApiResource in your schema will result in the generation of type implementing the Node interface and allow you to specify operations for it:
#[Jav\ApiTopiaBundle\Api\GraphQL\Attributes\ApiResource(
graphQLOperations: [...]
)]
class User
{
public string $id;
public ?string $name;
public string $email;
}
The above example will produce the following schema:
interface Node {
id: ID!
}
type User implements Node {
id: ID! # This is the id field that every Node type must have (see https://relay.dev/docs/guides/graphql-server-specification/)
_id: String! # This *new* property is the same type and will contain the exact value as the $id field defined in the DTO
name: String
email: String!
}
It is however possible to define a class that is not an ApiResource. This will result in the generation of a simple object type:
class User
{
public string $id;
public ?string $name;
public string $email;
}
The above example will produce the following schema*:
type User {
id: String!
name: String
email: String!
}
The limitation here is that it will not be possible to expose operations on this type.
*The type will be exposed only if it is referenced by an ApiResource or another exposed type.
The type of field exposed in the schema is determined with (by order of priority):
- PHP Reflection on the field
- PHP DocBlock on the field
When specifying a collection type (php array or iterable), the item type has to be specified in the docblock:
class User
{
/** @var string[] */
public array $roles;
}
Queries are exposed by adding the Query
attribute to an ApiResource class:
#[Jav\ApiTopiaBundle\Api\GraphQL\Attributes\ApiResource(
graphQLOperations: [
new Jav\ApiTopiaBundle\Api\GraphQL\Attributes\Query(
name: "user",
args: ['id' => ['type' => 'Int!']],
resolver: UserResolver::class
)
]
)]
class User
{
...
}
type User implements Node {
...
}
type Query {
user(id: Int!): User
}
name
: The name of the query in the schema (if left empty, the resource name will be used in camelCase)args
: An array of arguments for the query. The key is the name of the argument and the value is an array containing the following keys:type
: The type of the argument. Can be a scalar type, a custom type or a type defined in the schema (see below)defaultValue
: The default value for the argumentdescription
: The description of the argument
resolver
: The FQCN that will resolve the query. It must implement theJav\ApiTopiaBundle\Api\GraphQL\Resolver\QueryItemResolverInterface
interface.description
: The description of the query (optional)output
: The FQCN of the type that will be returned by the query. If not specified, the type will be inferred from the class this attribute is found on.
Query collections are exposed by adding the QueryCollection
attribute to an ApiResource class:
#[Jav\ApiTopiaBundle\Api\GraphQL\Attributes\ApiResource(
graphQLOperations: [
new Jav\ApiTopiaBundle\Api\GraphQL\Attributes\QueryCollection(
name: "users",
args: ['active' => ['type' => 'Boolean!']],
resolver: UserCollectionResolver::class
)
]
)]
class User
{
...
}
type User implements Node {
...
}
type Query {
users(active: Boolean!): [User!]
}
name
: The name of the query collection in the schema (if left empty, the resource name will be used in camelCase)args
: An array of arguments for the query collection. The key is the name of the argument and the value is an array containing the following keys:type
: The type of the argument. Can be a scalar type, a custom type or a type defined in the schema (see below)defaultValue
: The default value for the argumentdescription
: The description of the argument
resolver
: The FQCN that will resolve the query collection. It must implement theJav\ApiTopiaBundle\Api\GraphQL\Resolver\QueryCollectionResolverInterface
interface.description
: The description of the query collection (optional)paginationEnabled
: Wether or not the query collection should be paginated (default: true)paginationType
: The type of pagination to use (either 'offset' or 'cursor', default: 'cursor')output
: The FQCN of the type that will be returned by the query collection. If not specified, the type will be inferred from the class this attribute is found on.
Mutations are exposed by adding the Mutation
attribute to an ApiResource class:
#[Jav\ApiTopiaBundle\Api\GraphQL\Attributes\ApiResource(
graphQLOperations: [
new Jav\ApiTopiaBundle\Api\GraphQL\Attributes\Mutation(
name: "createUser",
input: CreateUserInput::class,
resolver: CreateUserResolver::class
)
]
)]
class User
{
...
}
type User implements Node {
...
}
type CreateUserInput {
...
}
type createUserPayload {
user: User
clientMutationId: String
}
type Mutation {
createUser(input: CreateUserInput!): createUserPayload
}
or with args instead:
#[Jav\ApiTopiaBundle\Api\GraphQL\Attributes\ApiResource(
graphQLOperations: [
new Jav\ApiTopiaBundle\Api\GraphQL\Attributes\Mutation(
name: "createUser",
args: ['objectInput' => ['type' => 'CreateUserInput!']],
resolver: CreateUserResolver::class
)
]
)]
class User
{
...
}
type User implements Node {
...
}
type CreateUserInput {
...
}
type createUserInput {
objectInput: CreateUserInput!
clientMutationId: String
}
type createUserPayload {
user: User
clientMutationId: String
}
type Mutation {
createUser(input: createUserInput!): createUserPayload
}
name
: The name of the mutation in the schema (mandatory)input
: The FQCN of the input type for the mutation (optional)resolver
: The FQCN that will resolve the mutation. It must implement theJav\ApiTopiaBundle\Api\GraphQL\Resolver\MutationResolverInterface
interface.description
: The description of the mutation (optional)args
: An array of arguments for the mutation. The key is the name of the argument and the value is an array containing the following keys:type
: The type of the argument. Can be a scalar type, a custom type or a type defined in the schema (see below)defaultValue
: The default value for the argumentdescription
: The description of the argument
output
: The FQCN of the type that will be returned by the mutation. If not specified, the type will be inferred from the class this attribute is found on.deserialize
: Wether or not the input should be deserialized before being passed to the resolver (default: true)