mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-16 12:23:15 +03:00
Work in progress on better docs (added docs for interfaces and unions)
This commit is contained in:
parent
360bf39c9b
commit
3514b5ac83
@ -1,36 +0,0 @@
|
|||||||
# Interfaces
|
|
||||||
In GraphQL an Interface is an abstract type that includes a certain set of fields that a
|
|
||||||
type must include to implement the interface.
|
|
||||||
|
|
||||||
In **graphql-php** interface type is an instance of `GraphQL\Type\Definition\InterfaceType`
|
|
||||||
(or one of it subclasses) which accepts configuration array in constructor:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
|
||||||
use GraphQL\Type\Definition\Type;
|
|
||||||
|
|
||||||
$characterInterface = 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 ($obj) {
|
|
||||||
if ($obj->type === 'human') {
|
|
||||||
return MyTypes::human();
|
|
||||||
} else {
|
|
||||||
return MyTypes::droid();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
# Abstract Type Resolution
|
|
127
docs/type-system/interfaces.md
Normal file
127
docs/type-system/interfaces.md
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
In **graphql-php** interface type is an instance of `GraphQL\Type\Definition\InterfaceType`
|
||||||
|
(or one of it subclasses) which accepts configuration array in constructor:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
|
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) {
|
||||||
|
if ($value->type === 'human') {
|
||||||
|
return MyTypes::human();
|
||||||
|
} else {
|
||||||
|
return MyTypes::droid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
This example uses **inline** style for Interface definition, but there are also
|
||||||
|
[other styles](/type-system/#type-definition-styles) (using inheritance or composition).
|
||||||
|
|
||||||
|
# Configuration options
|
||||||
|
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](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
|
resolveType | `callback` returning instance of `ObjectType` | **function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)** Any `callable` that receives `$value` from resolver of the parent field and returns concrete interface implementor for that `$value`.
|
||||||
|
|
||||||
|
# Implementing interface
|
||||||
|
To implement the Interface simply add it to **interfaces** array of Object Type definition:
|
||||||
|
```php
|
||||||
|
$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](#covariant-return-types-for-interface-fields) below)
|
||||||
|
|
||||||
|
# Covariant return types for interface fields
|
||||||
|
Object types implementing interface may change 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 re-use field definitions of Interface in Object Types:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$humanType = new ObjectType([
|
||||||
|
'name' => 'Human',
|
||||||
|
'interfaces' => [
|
||||||
|
$character
|
||||||
|
],
|
||||||
|
'fields' => [
|
||||||
|
'height' => Type::float(),
|
||||||
|
$character->getField('id'),
|
||||||
|
$character->getField('name')
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case field definitions are created only once (as a part of Interface Type) and then
|
||||||
|
re-used by all interface implementors. It can save several microseconds and memory + ensures that
|
||||||
|
field definitions of Interface and implementors are always in sync.
|
||||||
|
|
||||||
|
Yet it creates a problem with resolution of such fields. There are two ways how shared fields could
|
||||||
|
be resolved:
|
||||||
|
|
||||||
|
1. If field resolution algorithm is the same for all Interface implementors - you can simply add
|
||||||
|
**resolve** option to field definition in Interface itself.
|
||||||
|
|
||||||
|
2. If field resolution varies from implementor to implementor - you can specify **resolveField**
|
||||||
|
option in [Object Type config](/type-system/object-types/#configuration-options) and handle field
|
||||||
|
resolutions there
|
||||||
|
(Note: **resolve** option in field definition has precedence over **resolveField** option in object type definition)
|
||||||
|
|
||||||
|
# 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 **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.
|
36
docs/type-system/unions.md
Normal file
36
docs/type-system/unions.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Union Type Definition
|
||||||
|
A Union is an abstract type that simply enumerates other Object Types.
|
||||||
|
Value of Union Type is actually a value of one of included Object Types.
|
||||||
|
|
||||||
|
In **graphql-php** union type is an instance of `GraphQL\Type\Definition\UnionType`
|
||||||
|
(or one of it subclasses) which accepts configuration array in constructor:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$searchResultType = new UnionType([
|
||||||
|
'name' => 'SearchResult',
|
||||||
|
'types' => [
|
||||||
|
MyTypes::story(),
|
||||||
|
MyTypes::user()
|
||||||
|
];
|
||||||
|
'resolveType' => function($value) {
|
||||||
|
if ($value->type === 'story') {
|
||||||
|
return MyTypes::story();
|
||||||
|
} else {
|
||||||
|
return MyTypes::user();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
This example uses **inline** style for Union definition, but there are also
|
||||||
|
[other styles](/type-system/#type-definition-styles) (using inheritance or composition).
|
||||||
|
|
||||||
|
# Configuration options
|
||||||
|
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](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
|
resolveType | `callback` returning instance of `ObjectType` | **function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)** Any `callable` that receives `$value` from resolver of the parent field and returns Object Type for that `$value`.
|
@ -8,8 +8,10 @@ pages:
|
|||||||
- Scalar Types: type-system/scalar-types.md
|
- Scalar Types: type-system/scalar-types.md
|
||||||
- Enumeration Types: type-system/enum-types.md
|
- Enumeration Types: type-system/enum-types.md
|
||||||
- Lists and Non-Null: type-system/lists-and-nonnulls.md
|
- Lists and Non-Null: type-system/lists-and-nonnulls.md
|
||||||
- Interfaces and Unions: type-system/abstract-types.md
|
- Interfaces: type-system/interfaces.md
|
||||||
|
- Unions: type-system/unions.md
|
||||||
- Defining Schema: type-system/schema.md
|
- Defining Schema: type-system/schema.md
|
||||||
|
- Custom Metadata: type-system/metadata.md
|
||||||
- Data Fetching: data-fetching.md
|
- Data Fetching: data-fetching.md
|
||||||
- Best Practices: best-practices.md
|
- Best Practices: best-practices.md
|
||||||
- Complementary Tools: complementary-tools.md
|
- Complementary Tools: complementary-tools.md
|
||||||
|
Loading…
x
Reference in New Issue
Block a user