File: README.md
graphql-php
This repository is planned to move to a new home.
See the announcement for details and to share feedback.
This is a PHP implementation of the GraphQL specification
based on the reference implementation in JavaScript.
Fully compliant with the October 2021 GraphQL specification.
September 2025 specification compliance is in progress.
Sponsors
If you make money using this project, please consider sponsoring its maintainer on GitHub Sponsors or the project on OpenCollective.
Installation
Via composer:
composer require webonyx/graphql-phpDocumentation
Full documentation is available at https://webonyx.github.io/graphql-php
or in the docs directory.
Examples
There are several ready examples in the examples directory,
with a specific README file per example.
Versioning
This project follows Semantic Versioning 2.0.0.
Elements that belong to the public API of this package are marked with the @api PHPDoc tag.
Constants included in the class-reference docs are also part of the public API.
Those elements are thus guaranteed to be stable within major versions.
All other elements are not part of this backwards compatibility guarantee and may change between minor or patch versions.
The most recent version is actively developed on master.
Older versions are generally no longer supported, although exceptions may be made for sponsors.
File: docs/type-definitions/directives.md
Built-in directives
The directive is a way for a client to give GraphQL server additional context and hints on how to execute
the query. The directive can be attached to a field or fragment and can affect the execution of the
query in any way the server desires.
The GraphQL specification includes the following built-in directives:
- @include(if: Boolean) Only include this field or fragment in the result if the argument is true
- @skip(if: Boolean) Skip this field or fragment if the argument is true
- @deprecated(reason: String) Marks a field, argument, input field, or enum value as deprecated with an optional reason
- @specifiedBy(url: String!) Links a custom scalar type to a human-readable specification URL
- @oneOf Marks an input object type as a "oneof" input, requiring exactly one field to be non-null
For example:
query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}Here if $withFriends variable is set to false - friends section will be ignored and excluded
from the response. Important implementation detail: those fields will never be executed
(not just removed from response after execution).
Custom directives
graphql-php supports custom directives even though their presence does not affect the execution of fields.
You can use GraphQL\Type\Definition\ResolveInfo
in field resolvers to modify the output depending on those directives or perform statistics collection.
Other use case is your own query validation rules relying on custom directives.
In graphql-php custom directive is an instance of GraphQL\Type\Definition\Directive
(or one of its subclasses) which accepts an array of following options:
use GraphQL\Language\DirectiveLocation;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\Directive;
$trackDirective = new Directive([
'name' => 'track',
'description' => 'Instruction to record usage of the field by client',
'locations' => [
DirectiveLocation::FIELD,
],
'args' => [
'details' => [
'type' => Type::string(),
'description' => 'String with additional details of field usage scenario',
'defaultValue' => ''
]
]
]);See possible directive locations inGraphQL\Language\DirectiveLocation.
File: docs/type-definitions/enums.md
Enum Type Definition
Enumeration types are a special kind of scalar that is restricted to a particular set
of allowed values.
Writing Enum Types
In graphql-php enum type is an instance of GraphQL\Type\Definition\EnumType
which accepts configuration array in constructor:
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' => 'Episode',
'description' => 'One of the films in the Star Wars Trilogy',
'values' => [
'NEWHOPE' => [
'value' => 4,
'description' => 'Released in 1977.'
],
'EMPIRE' => [
'value' => 5,
'description' => 'Released in 1980.'
],
'JEDI' => [
'value' => 6,
'description' => 'Released in 1983.'
],
]
]);This example uses an inline style for Enum Type definition, but you can also use
inheritance or schema definition language.
Configuration options
Enum Type constructor accepts an array with following options:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Name of the type. When not set - inferred from array key (read about shorthand field definition below) |
| description | string |
Plain-text description of the type for clients (e.g. used by GraphiQL for auto-generated documentation) |
| values | array |
List of enumerated items, see below for expected structure of each entry |
Each entry of values array in turn accepts following options:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Name of the item. When not set - inferred from array key (read about shorthand field definition below) |
| value | mixed |
Internal representation of enum item in your application (could be any value, including complex objects or callbacks) |
| description | string |
Plain-text description of enum value for clients (e.g. used by GraphiQL for auto-generated documentation) |
| deprecationReason | string |
Text describing why this enum value is deprecated. When not empty - item will not be returned by introspection queries (unless forced) |
Construction from PHP enum
You can reuse your existing PHP enums in GraphQL.
Leverage PHP attributes to add descriptions and deprecate values:
use GraphQL\Type\Definition\Deprecated;
use GraphQL\Type\Definition\Description;
#[Description(description: 'Sweet and juicy.')]
enum Fruit
{
#[Description(description: 'Rich in potassium.')]
case BANANA;
#[Deprecated(reason: 'Too sour.')]
case CITRON;
}PhpDocs will be used as descriptions if present, but are overridden by the Description attribute.
Wrap them with GraphQL\Type\Definition\PhpEnumType to use them in a GraphQL schema:
use GraphQL\Type\Definition\PhpEnumType;
$fruitEnumType = new PhpEnumType(Fruit::class);The following type will be deduced from Fruit:
"""
Sweet and juicy.
"""
enum Fruit {
"""
Rich in potassium.
"""
BANANA
CITRON @deprecated(reason: "Too sour.")
}Conversion rules:
- Client-given arguments will be converted to enum instances
- Returned output values are expected to be enum instances
Shorthand definitions
If internal representation of enumerated item is the same as item name, then you can use
following shorthand for definition:
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' => 'Episode',
'description' => 'One of the films in the Star Wars Trilogy',
'values' => ['NEWHOPE', 'EMPIRE', 'JEDI']
]);which is equivalent of:
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' => 'Episode',
'description' => 'One of the films in the Star Wars Trilogy',
'values' => [
'NEWHOPE' => ['value' => 'NEWHOPE'],
'EMPIRE' => ['value' => 'EMPIRE'],
'JEDI' => ['value' => 'JEDI']
]
]);which is in turn equivalent of the full form:
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' => 'Episode',
'description' => 'One of the films in the Star Wars Trilogy',
'values' => [
['name' => 'NEWHOPE', 'value' => 'NEWHOPE'],
['name' => 'EMPIRE', 'value' => 'EMPIRE'],
['name' => 'JEDI', 'value' => 'JEDI']
]
]);Field Resolution
When object field is of Enum Type, field resolver is expected to return an internal
representation of corresponding Enum item (value in config). graphql-php will
then serialize this value to name to include in response:
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\ObjectType;
$episodeEnum = new EnumType([
'name' => 'Episode',
'description' => 'One of the films in the Star Wars Trilogy',
'values' => [
'NEWHOPE' => [
'value' => 4,
'description' => 'Released in 1977.'
],
'EMPIRE' => [
'value' => 5,
'description' => 'Released in 1980.'
],
'JEDI' => [
'value' => 6,
'description' => 'Released in 1983.'
],
]
]);
$heroType = new ObjectType([
'name' => 'Hero',
'fields' => [
'appearsIn' => [
'type' => $episodeEnum,
// Actual entry in response will be 'appearsIn' => 'EMPIRE'
'resolve' => fn (): int => 5,
]
]
]);The Reverse is true when the enum is used as input type (e.g. as field argument).
GraphQL will treat enum input as name and convert it into value before passing to your app.
For example, given object type definition:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$heroType = new ObjectType([
'name' => 'Hero',
'fields' => [
'appearsIn' => [
'type' => Type::boolean(),
'args' => [
'episode' => Type::nonNull($enumType)
],
'resolve' => fn ($hero, array $args): bool => $args['episode'] === 5,
]
]
]);Then following query:
fragment on Hero {
appearsInNewHope: appearsIn(NEWHOPE)
appearsInEmpire: appearsIn(EMPIRE)
}will return:
[
'appearsInNewHope' => false,
'appearsInEmpire' => true
]File: docs/type-definitions/index.md
Type Definitions
graphql-php represents a type as a class instance from the GraphQL\Type\Definition namespace:
Input vs. Output Types
All types in GraphQL are of two categories: input and output.
Obviously, NonNull and List types belong to both categories depending on their
inner type.
Definition styles
Several styles of type definitions are supported depending on your preferences.
Inline definitions
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
$myType = new ObjectType([
'name' => 'MyType',
'fields' => [
'id' => Type::id()
]
]);Class per type
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
class MyType extends ObjectType
{
public function __construct()
{
$config = [
// Note: 'name' is not needed in this form:
// it will be inferred from class name by omitting namespace and dropping "Type" suffix
'fields' => [
'id' => Type::id()
]
];
parent::__construct($config);
}
}Schema definition language
schema {
query: Query
mutation: Mutation
}
type Query {
greetings(input: HelloInput!): String!
}
input HelloInput {
firstName: String!
lastName: String
}Read more about building an executable schema using schema definition language.
File: docs/type-definitions/inputs.md
Input Object Type Definition
The GraphQL specification defines the Input Object type for complex inputs.
It is similar to the Object type, but its fields have no args or resolve options and their type must be input type.
Writing Input Object Types
In graphql-php, Input Object Type is an instance of GraphQL\Type\Definition\InputObjectType
(or one of its subclasses) which accepts configuration array in its constructor:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectType;
$filters = new InputObjectType([
'name' => 'StoryFiltersInput',
'fields' => [
'author' => [
'type' => Type::id(),
'description' => 'Only show stories with this author id'
],
'popular' => [
'type' => Type::boolean(),
'description' => 'Only show popular stories (liked by several people)'
],
'tags' => [
'type' => Type::listOf(Type::string()),
'description' => 'Only show stories which contain all of those tags'
]
]
]);Every field may be of other InputObjectType (thus complex hierarchies of inputs are possible)
Configuration options
The constructor of InputObjectType accepts an array with the following options:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Unique name of this object type within Schema |
| description | string |
Plain-text description of this type for clients (e.g. used by GraphiQL for auto-generated documentation) |
| isOneOf | bool |
Indicates that an Input Object is a OneOf Input Object (and thus requires exactly one of its fields be provided). |
| parseValue | callable(array<string, mixed>): mixed |
Converts incoming values from their array representation to something else (e.g. a value object) |
| fields | iterable<FieldConfig> or callable(): iterable<FieldConfig> |
Required. An iterable describing object fields or callable returning such an iterable (see below). |
Every entry in fields is an array with following entries:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Name of the input field. When not set - inferred from fields array key |
| type | Type |
Required. Instance of one of Input Types (Scalar, Enum, InputObjectType + any combination of those with nonNull and listOf modifiers) |
| defaultValue | scalar |
Default value of this input field. Use the internal value if specifying a default for an enum type |
| description | string |
Plain-text description of this input field for clients (e.g. used by GraphiQL for auto-generated documentation) |
| deprecationReason | string |
Plain-test reason for why this input field is deprecated. |
Using Input Object Type
In the example above we defined our InputObjectType StoryFiltersInput.
Now let's use it in one of field arguments:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$queryType = new ObjectType([
'name' => 'Query',
'fields' => [
'stories' => [
'type' => Type::listOf($storyType),
'args' => [
'filters' => [
'type' => $filters,
'defaultValue' => [
'popular' => true,
],
],
],
'resolve' => fn ($rootValue, array $args): array => DataSource::filterStories($args['filters']),
],
],
]);You can define defaultValue for fields with complex inputs as an associative array.
Then GraphQL query could include filters as a literal value:
{
stories(filters: {
author: "1"
popular: false
}) {
...
}
}Or as a query variable:
query ($filters: StoryFiltersInput!) {
stories(filters: $filters) {
...
}
}{
"filters": {
"author": "1",
"popular": false
}
}graphql-php will validate the input against your InputObjectType definition and pass it to your resolver as $args['filters'].
Converting Input Array to Value Object
If you want more type safety you can choose to parse the input array into a value object.
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectType;
final readonly class StoryFiltersInput
{
public function __construct(
public string $author,
public ?bool $popular,
/** @var array<string> */
public array $tags
) {}
}
$filters = new InputObjectType([
'name' => 'StoryFiltersInput',
'fields' => [
'author' => [
'type' => Type::nonNull(Type::string()),
],
'popular' => [
'type' => Type::boolean(),
],
'tags' => [
'type' => Type::nonNull(Type::listOf(Type::string())),
]
],
'parseValue' => fn (array $values): StoryFiltersInput => new StoryFiltersInput(
author: $values['author'],
popular: $values['popular'] ?? null,
tags: $values['tags'],
),
]);The value of $args['filters'] will now be an instance of StoryFiltersInput.
The incoming values are converted using a depth-first traversal.
Thus, nested input values will be passed through their respective parseValue functions before the parent receives their value.
Using the `isOneOf` Configuration Option
The isOneOf configuration option allows you to declare an input object as a OneOf Input Object.
This means that exactly one of its fields must be provided when the input is used.
This is useful when an argument can accept several alternative values, but never more than one at the same time.
Suppose you want to allow a query to filter stories either by author or by tag, but not both together.
You can define an input object with isOneOf: true:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectType;
$storySearch = new InputObjectType([
'name' => 'StorySearchInput',
'isOneOf' => true,
'fields' => [
'author' => [
'type' => Type::id(),
'description' => 'Find stories by a specific author',
],
'tag' => [
'type' => Type::string(),
'description' => 'Find stories with a specific tag',
],
],
]);This input object can then be used as an argument in a query:
$searchType = new ObjectType([
'name' => 'Query',
'fields' => [
'searchStories' => [
'type' => Type::listOf($storyType),
'args' => [
'search' => [
'type' => $storySearch,
],
],
'resolve' => fn ($rootValue, array $args): array => DataSource::searchStories($args['search']),
],
],
]);{
searchStories(search: { author: "1" }) {
id
title
}
}If you try to provide both fields at once, validation will fail:
{
searchStories(search: { author: "1", tag: "php" }) {
id
title
}
}graphql-php ensures that with isOneOf: true, exactly one field is set.
This helps make APIs clearer and less error-prone when alternative inputs are required.
File: docs/type-definitions/interfaces.md
Interface Type Definition
An Interface is an abstract type that includes a certain set of fields that a
type must include to implement the interface.
Writing Interface Types
In graphql-php interface type is an instance of GraphQL\Type\Definition\InterfaceType
(or one of its subclasses) which accepts configuration array in a constructor:
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
$character = new InterfaceType([
'name' => 'Character',
'description' => 'A character in the Star Wars Trilogy',
'fields' => [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the character.',
],
'name' => [
'type' => Type::string(),
'description' => 'The name of the character.'
]
],
'resolveType' => function ($value): ObjectType {
switch ($value->type ?? null) {
case 'human': return MyTypes::human();
case 'droid': return MyTypes::droid();
default: throw new Exception("Unknown Character type: {$value->type ?? null}");
}
}
]);This example uses inline style for Interface definition, but you can also use
inheritance or schema definition language.
Configuration options
The constructor of InterfaceType accepts an array. Below is a full list of allowed options:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Unique name of this interface type within Schema |
| fields | array |
Required. List of fields required to be defined by interface implementors. Same as Fields for Object Type |
| description | string |
Plain-text description of this type for clients (e.g. used by GraphiQL for auto-generated documentation) |
| resolveType | callback |
function ($value, $context, ResolveInfo $info) Receives $value from resolver of the parent field and returns concrete interface implementor for this $value. |
Implementing interface
To implement the Interface simply add it to interfaces array of Object Type definition:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
'name' => 'Human',
'fields' => [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the character.',
],
'name' => [
'type' => Type::string(),
'description' => 'The name of the character.'
]
],
'interfaces' => [
$character
]
]);Note that Object Type must include all fields of interface with exact same types
(including nonNull specification) and arguments.
The only exception is when object's field type is more specific than the type of this field defined in interface
(see Covariant return types for interface fields below)
Covariant return types for interface fields
Object types implementing interface may change the field type to more specific.
Example:
interface A {
field1: A
}
type B implements A {
field1: B
}Sharing Interface fields
Since every Object Type implementing an Interface must have the same set of fields - it often makes
sense to reuse field definitions of Interface in Object Types:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
'name' => 'Human',
'interfaces' => [
$character
],
'fields' => [
$character->getField('id'),
$character->getField('name'),
[
'name' => 'height',
'type' => Type::float(),
],
]
]);In this case, field definitions are created only once (as a part of the Interface Type) and then reused by all interface implementors.
It can save several microseconds and kilobytes and ensures that field definitions of Interface and implementors are always in sync.
Yet it creates a problem with the resolution of such fields.
There are two ways how shared fields could be resolved:
If the field resolution algorithm is the same for all Interface implementors,
you can add the resolve option to the field definition in the Interface itself.If field resolution varies for different implementations, you can specify the resolveField option
in the Object Type config and handle field resolutions there.
(Note: The resolve option in field definitions has precedence over the resolveField option in object type definitions.)
Interface role in data fetching
The only responsibility of interface in Data Fetching process is to return concrete Object Type
for given $value in resolveType. Then resolution of fields is delegated to resolvers of this
concrete Object Type.
If a resolveType option is omitted, graphql-php will loop through all interface implementors and
use their isTypeOf callback to pick the first suitable one. This is obviously less efficient
than single resolveType call. So it is recommended to define resolveType whenever possible.
Prevent invisible types
When object types that implement an interface are not directly referenced by a field, they cannot
be discovered during schema introspection. For example:
type Query {
animal: Animal
}
interface Animal {...}
type Cat implements Animal {...}
type Dog implements Animal {...}In this example, Cat and Dog would be considered invisible types. Querying the animal field
would fail, since no possible implementing types for Animal can be found.
There are two possible solutions:
Add fields that reference the invisible types directly, e.g.:
graphqltype Query { dog: Dog cat: Cat }Pass the invisible types during schema construction, e.g.:
new GraphQLSchema([
'query' => ...,
'types' => [$cat, $dog]
]);File: docs/type-definitions/lists-and-nonnulls.md
Lists
graphql-php provides built-in support for lists. In order to create list type - wrap
existing type with GraphQL\Type\Definition\Type::listOf() modifier:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$userType = new ObjectType([
'name' => 'User',
'fields' => [
'emails' => [
'type' => Type::listOf(Type::string()),
'resolve' => fn (): array => [
'[email protected]',
'[email protected]'
],
]
]
]);Resolvers for such fields are expected to return array or instance of PHP's built-in Traversable
interface (null is allowed by default too).
If returned value is not of one of these types - graphql-php will add an error to result
and set the field value to null (only if the field is nullable, see below for non-null fields).
Non-Nulls
By default, every field or argument can have a null value.
To indicate the value must be non-null use the GraphQL\Type\Definition\Type::nonNull() modifier:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
'name' => 'User',
'fields' => [
'id' => [
'type' => Type::nonNull(Type::id()),
'resolve' => fn (): string => uniqid(),
],
'emails' => [
'type' => Type::nonNull(Type::listOf(Type::string())),
'resolve' => fn (): array => [
'[email protected]',
'[email protected]'
],
]
]
]);If resolver of non-null field returns null, graphql-php will add an error to
result and exclude the whole object from the output (an error will bubble to first
nullable parent field which will be set to null).
Read the section on Data Fetching for details.
File: docs/type-definitions/object-types.md
Object Type Definition
Object Type is the most frequently used primitive in a typical GraphQL application.
Conceptually Object Type is a collection of Fields. Each field, in turn,
has its own type which allows building complex hierarchies.
Writing Object Types
In graphql-php object type is an instance of GraphQL\Type\Definition\ObjectType
(or one of its subclasses) which accepts a configuration array in its constructor:
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Examples\Blog\Data\DataSource;
use GraphQL\Examples\Blog\Data\Story;
$userType = new ObjectType([
'name' => 'User',
'description' => 'Our blog visitor',
'fields' => [
'firstName' => [
'type' => Type::string(),
'description' => 'User first name'
],
'email' => Type::string()
]
]);
$blogStory = new ObjectType([
'name' => 'Story',
'fields' => [
'body' => Type::string(),
'author' => [
'type' => $userType,
'description' => 'Story author',
'resolve' => fn (Story $blogStory): ?User => DataSource::findUser($blogStory->authorId),
],
'likes' => [
'type' => Type::listOf($userType),
'description' => 'List of users who liked the story',
'args' => [
'limit' => [
'type' => Type::int(),
'description' => 'Limit the number of recent likes returned',
'defaultValue' => 10
]
],
'resolve' => fn (Story $blogStory, array $args): array => DataSource::findLikes($blogStory->id, $args['limit']),
]
]
]);This example uses inline style for Object Type definitions, but you can also use
inheritance or schema definition language.
Configuration options
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Unique name of this object type within Schema |
| fields | array or callable |
Required. An array describing object fields or callable returning such an array. See field configuration options section below for expected structure of each array entry. See also the section on Circular types for an explanation of when to use callable for this option. |
| description | string |
Plain-text description of this type for clients (e.g. used by GraphiQL for auto-generated documentation) |
| interfaces | array or callable |
List of interfaces implemented by this type or callable returning such a list. See Interface Types for details. See also the section on Circular types for an explanation of when to use callable for this option. |
| isTypeOf | callable |
function ($value, $context, ResolveInfo $info): bool Expected to return true if $value qualifies for this type (see section about Abstract Type Resolution for explanation). |
| resolveField | callable |
function ($value, array $args, $context, ResolveInfo $info): mixed Given the $value of this type, it is expected to return value for a field defined in $info->fieldName. A good place to define a type-specific strategy for field resolution. See Data Fetching for details. |
| argsMapper | callable |
function (array $args, FieldDefinition, FieldNode): mixed Called once, when Executor resolves arguments for given field. Could be used to validate args and/or to map them to DTO/Object. |
| visible | bool or callable |
Defaults to true. The given callable receives no arguments and is expected to return a bool, it is called once when the field may be accessed. The field is treated as if it were not defined at all when this is false. |
Field configuration options
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Name of the field. When not set - inferred from fields array key (read about shorthand field definition below) |
| type | Type |
Required. An instance of internal or custom type. Note: type must be represented by a single instance within one schema (see also lazy loading of types) |
| args | array |
An array describing any number of possible field arguments, each element being an array. See field argument configuration options. |
| resolve | callable |
function ($objectValue, array $args, $context, ResolveInfo $info): mixed Given the $objectValue of this type, it is expected to return actual value of the current field. See section on Data Fetching for details |
| complexity | callable |
function (int $childrenComplexity, array $args): int Used to restrict query complexity. The feature is disabled by default, read about Security to use it. |
| description | string |
Plain-text description of this field for clients (e.g. used by GraphiQL for auto-generated documentation) |
| deprecationReason | string |
Text describing why this field is deprecated. When not empty - field will not be returned by introspection queries (unless forced) |
Field argument configuration options
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Name of the argument. When not set - inferred from args array key |
| type | Type |
Required. Instance of one of Input Types (scalar, enum, InputObjectType + any combination of those with nonNull and listOf modifiers) |
| description | string |
Plain-text description of this argument for clients (e.g. used by GraphiQL for auto-generated documentation) |
| defaultValue | scalar |
Default value for this argument. Use the internal value if specifying a default for an enum type |
Shorthand field definitions
Fields can be also defined in shorthand notation (with only name and type options):
'fields' => [
'id' => Type::id(),
'fieldName' => $fieldType
]which is equivalent of:
'fields' => [
'id' => ['type' => Type::id()],
'fieldName' => ['type' => $fieldName]
]which is in turn equivalent of the full form:
'fields' => [
['name' => 'id', 'type' => Type::id()],
['name' => 'fieldName', 'type' => $fieldName]
]Same shorthand notation applies to field arguments as well.
Recurring and circular types
Almost all real-world applications contain recurring or circular types.
Think user friends or nested comments for example.
graphql-php allows such types, but you have to use callable in
option fields (and/or interfaces).
For example:
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$userType = new ObjectType([
'name' => 'User',
'fields' => function () use (&$userType): array {
return [
'email' => [
'type' => Type::string()
],
'friends' => [
'type' => Type::listOf($userType)
]
];
},
]);Same example for inheritance style of type definitions
using a type registry (see lazy loading of types):
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
class UserType extends ObjectType
{
public function __construct()
{
parent::__construct([
'fields' => [
'email' => fn (): ScalarType => MyTypes::string(),
'friends' => fn (): ListOfType => MyTypes::listOf(MyTypes::user())
],
]);
}
}
class MyTypes
{
private static UserType $user;
public static function user(): UserType
{
return self::$user ??= new UserType();
}
public static function string(): ScalarType
{
return Type::string();
}
public static function listOf($type): ListOfType
{
return Type::listOf($type);
}
}Field Resolution
Field resolution is the primary mechanism in graphql-php for returning actual data for your fields.
It is implemented using a resolveField callable in type definitions,
or a resolve callable in field definitions (the latter has precedence).
Read the section on Data Fetching for a complete description of this process.
Custom Metadata
All types in graphql-php accept a configuration array.
In some cases, you may be interested in passing your own metadata for type or field definition.
graphql-php preserves the original configuration array in every type or field instance in a public property $config.
You may use it for custom implementations that are not natively supported by this library.
File: docs/type-definitions/scalars.md
Scalar Type Definition
Scalar types represent primitive leaf values in a GraphQL type system.
When object fields have to resolve to some concrete data, that's where the scalar types come in.
Built-in Scalar Types
The GraphQL specification describes several built-in scalar types. In graphql-php they are
exposed as static methods of the class GraphQL\Type\Definition\Type:
use GraphQL\Type\Definition\Type;
// Built-in Scalar types:
Type::string(); // String type
Type::int(); // Int type
Type::float(); // Float type
Type::boolean(); // Boolean type
Type::id(); // ID typeThose methods return instances of a subclass of GraphQL\Type\Definition\ScalarType.
Use them directly in type definitions or wrapped in a type registry (see lazy loading of types).
Writing Custom Scalar Types
In addition to built-in scalars, you can define your own scalar types with additional validation.
Typical examples of such types are Email, Date, Url, etc.
In order to implement your own type, you must understand how scalars are handled in GraphQL.
GraphQL deals with scalars in the following cases:
Convert the internal representation of a value, returned by your app (e.g. stored in a database
or hardcoded in the source code), to a serialized representation included in the response.Convert an input value, passed by a client in variables along with a GraphQL query, to
its internal representation used in your application.Convert an input literal value, hardcoded in a GraphQL query (e.g. field argument value), to
its internal representation used in your application.
Those cases are covered by the methods serialize, parseValue and parseLiteral of the
abstract class ScalarType respectively.
Here is an example of a simple Email type:
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Utils\Utils;
class EmailType extends ScalarType
{
// Note: name can be omitted. In this case it will be inferred from class name
// (suffix "Type" will be dropped)
public string $name = 'Email';
public function serialize($value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new InvariantViolation("Could not serialize following value as email: " . Utils::printSafe($value));
}
return $this->parseValue($value);
}
public function parseValue($value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new Error("Cannot represent following value as email: " . Utils::printSafeJson($value));
}
return $value;
}
public function parseLiteral(Node $valueNode, ?array $variables = null)
{
// Throw GraphQL\Error\Error vs \UnexpectedValueException to locate the error in the query
if (!$valueNode instanceof StringValueNode) {
throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, [$valueNode]);
}
if (!filter_var($valueNode->value, FILTER_VALIDATE_EMAIL)) {
throw new Error("Not a valid email", [$valueNode]);
}
return $valueNode->value;
}
}Or with inline style:
use GraphQL\Type\Definition\CustomScalarType;
$emailType = new CustomScalarType([
'name' => 'Email',
'serialize' => static function ($value) {/* See function body above */},
'parseValue' => static function ($value) {/* See function body above */},
'parseLiteral' => static function (Node $valueNode, ?array $variables = null) {/* See function body above */},
]);Keep in mind the passed functions will be called statically, so a passed in callable
such as [Foo::class, 'bar'] should only reference static class methods.
Linking a Scalar to Its Specification
The @specifiedBy built-in directive lets you attach a URL to a custom scalar that specifies the behavior of that scalar.
This URL is exposed through introspection and printed in SDL output.
Pass specifiedByURL when constructing the type:
use GraphQL\Type\Definition\CustomScalarType;
$uuidType = new CustomScalarType([
'name' => 'UUID',
'specifiedByURL' => 'https://tools.ietf.org/html/rfc4122',
'serialize' => static function ($value) { /* ... */ },
'parseValue' => static function ($value) { /* ... */ },
'parseLiteral' => static function ($valueNode, ?array $variables = null) { /* ... */ },
]);
$uuidType->specifiedByURL; // "https://tools.ietf.org/html/rfc4122"When building a schema from SDL, @specifiedBy is parsed automatically:
scalar UUID @specifiedBy(url: "https://tools.ietf.org/html/rfc4122")And SchemaPrinter will emit the directive when printing a schema that contains a scalar with a specifiedByURL.
Overriding Built-in Scalars
You can override built-in scalars (String, Int, Float, Boolean, ID) on a per-schema basis by passing a custom scalar with the same name through the types option.
This works with or without a typeLoader:
use GraphQL\Type\Definition\CustomScalarType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
$uppercaseString = new CustomScalarType([
'name' => 'String',
'serialize' => static fn ($value): string => strtoupper((string) $value),
]);
$schema = new Schema([
'query' => $queryType,
'typeLoader' => $myTypeLoader,
'types' => [$uppercaseString],
]);The custom scalar replaces the built-in one throughout the entire schema, affecting both serialization of results and coercion of inputs.
Note: The
typeLoaderis never called for built-in scalar names.
Always usetypesorscalarOverridesto override them.
Discovering overrides requires scanning types.
When types is a lazy callable, the scan resolves it on the first lookup of a built-in scalar - typically the first executed query.
To avoid this in schemas that use lazy loading of types, pass overrides explicitly through the scalarOverrides option instead - or pass an empty array to declare there are none:
$schema = new Schema([
'query' => $queryType,
'typeLoader' => $myTypeLoader,
'types' => $myLazyTypes,
'scalarOverrides' => [$uppercaseString], // or [] for none
]);File: docs/type-definitions/unions.md
Union Type Definition
A Union is an abstract type that simply enumerates other Object Types.
The value of Union Type is actually a value of one of included Object Types.
Writing Union Types
In graphql-php union type is an instance of GraphQL\Type\Definition\UnionType
(or one of its subclasses) which accepts configuration array in a constructor:
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\UnionType;
$searchResultType = new UnionType([
'name' => 'SearchResult',
'types' => [
MyTypes::story(),
MyTypes::user()
],
'resolveType' => function ($value): ObjectType {
switch ($value->type ?? null) {
case 'story': return MyTypes::story();
case 'user': return MyTypes::user();
default: throw new Exception("Unexpected SearchResult type: {$value->type ?? null}");
}
},
]);This example uses inline style for Union definition, but you can also use
inheritance or schema definition language.
Configuration options
The constructor of UnionType accepts an array. Below is a full list of allowed options:
| Option | Type | Notes |
|---|---|---|
| name | string |
Required. Unique name of this interface type within Schema |
| types | array |
Required. List of Object Types included in this Union. Note that you can't create a Union type out of Interfaces or other Unions. |
| description | string |
Plain-text description of this type for clients (e.g. used by GraphiQL for auto-generated documentation) |
| resolveType | callback |
function ($value, $context, ResolveInfo $info): ObjectType Receives $value from resolver of the parent field and returns concrete Object Type for this $value. |