mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 04:46:04 +03:00
Work in progress on better docs (added sections on directives and schema to docs)
This commit is contained in:
parent
add2621a33
commit
24b2285ffe
65
docs/type-system/directives.md
Normal file
65
docs/type-system/directives.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Built-in directives
|
||||||
|
Directive is a way to dynamically change the structure and shape of queries using variables.
|
||||||
|
Directive can be attached to a field or fragment inclusion, and can affect execution of the
|
||||||
|
query in any way the server desires.
|
||||||
|
|
||||||
|
GraphQL specification includes two 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`
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```graphql
|
||||||
|
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 response. Important implementation detail: those fields will never be executed
|
||||||
|
(and not just removed from response after execution).
|
||||||
|
|
||||||
|
# Custom directives
|
||||||
|
**graphql-php** supports custom directives even though their presence does not affect execution of fields.
|
||||||
|
But 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 it subclasses) which accepts an array with following options:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use GraphQL\Type\Definition\Directive;
|
||||||
|
use GraphQL\Type\Definition\FieldArgument;
|
||||||
|
|
||||||
|
$trackDirective = new Directive([
|
||||||
|
'name' => 'track',
|
||||||
|
'description' => 'Instruction to record usage of the field by client'
|
||||||
|
'locations' => [
|
||||||
|
Directive::LOCATION_FIELD,
|
||||||
|
],
|
||||||
|
'args' => [
|
||||||
|
new FieldArgument([
|
||||||
|
'name' => 'details',
|
||||||
|
'type' => Type::string(),
|
||||||
|
'description' => 'String with additional details of field usage scenario'
|
||||||
|
'defaultValue' => ''
|
||||||
|
])
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
Directive location can be one of the following values:
|
||||||
|
|
||||||
|
* `Directive::LOCATION_QUERY`
|
||||||
|
* `Directive::LOCATION_MUTATION`
|
||||||
|
* `Directive::LOCATION_SUBSCRIPTION`
|
||||||
|
* `Directive::LOCATION_FIELD`
|
||||||
|
* `Directive::LOCATION_FRAGMENT_DEFINITION`
|
||||||
|
* `Directive::LOCATION_FRAGMENT_SPREAD`
|
||||||
|
* `Directive::LOCATION_INLINE_FRAGMENT`
|
@ -156,3 +156,10 @@ introduce Dependency Injection Container if your types have other dependencies.
|
|||||||
|
|
||||||
Alternatively all methods of registry could be static if you prefer - then there is no need
|
Alternatively all methods of registry could be static if you prefer - then there is no need
|
||||||
to pass it in constructor - instead just use use `TypeRegistry::myAType()` in your type definitions.
|
to pass it in constructor - instead just use use `TypeRegistry::myAType()` in your type definitions.
|
||||||
|
|
||||||
|
# Custom Metadata
|
||||||
|
All types in **graphql-php** accept configuration array. In some cases you may be interested in
|
||||||
|
passing your own metadata for type or field definition.
|
||||||
|
|
||||||
|
**graphql-php** preserves original configuration array in every type or field instance in
|
||||||
|
public property `$config`. Use it to implement app-level mappings and definitions.
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
# Schema Definition
|
||||||
|
|
||||||
|
After all of your types are defined, you must define schema. Schema is a container for your type
|
||||||
|
hierarchy, which expects root type in constructor.
|
||||||
|
|
||||||
|
In **graphql-php** schema is an instance of `GraphQL\Schema` which accepts configuration array
|
||||||
|
in constructor:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => $queryType,
|
||||||
|
'mutation' => $mutationType,
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Configuration Options
|
||||||
|
|
||||||
|
Option | Type | Notes
|
||||||
|
------------ | -------- | -----
|
||||||
|
query | `ObjectType` | **Required.** Object type (usually named "Query") containing root-level fields of your read API
|
||||||
|
mutation | `ObjectType` | Object type (usually named "Mutation") containing root-level fields of your write API
|
||||||
|
subscription | `ObjectType` | Reserved for future subscriptions implementation. Currently presented for compatibility with introspection query of **graphql-js**, used by various clients (like Relay or GraphiQL)
|
||||||
|
directives | `Directive[]` | Full list of [directives](directives/) supported by your schema. By default contains built-in `@skip` and `@include` directives.<br><br> If you pass your own directives and still want to use built-in directives - add them explicitly. For example: `array_merge(GraphQL::getInternalDirectives(), [$myCustomDirective]`
|
||||||
|
types | `ObjectType[]` | List of object types which cannot be detected by **graphql-php** during static schema analysis.<br><br>Most often it happens when object type is never referenced in fields directly, but is still a part of schema because it implements an interface which resolves to this object type in it's `resolveType` callback. <br><br> Note that you are not required to pass all of your types here - it is simply a workaround for concrete use-case.
|
||||||
|
|
||||||
|
|
||||||
|
# Query and Mutation types
|
||||||
|
Schema consists of two special root types:
|
||||||
|
|
||||||
|
* `Query` type is a surface of your read API
|
||||||
|
* `Mutation` type (optional) exposes write API by declaring all possible mutations in your app.
|
||||||
|
|
||||||
|
Query and Mutation types are regular object types containing root-level fields of your API:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Schema;
|
||||||
|
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'hello' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function() {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'hero' => [
|
||||||
|
'type' => $characterInterface,
|
||||||
|
'args' => [
|
||||||
|
'episode' => [
|
||||||
|
'type' => $episodeEnum
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'resolve' => function ($rootValue, $args) {
|
||||||
|
return StarWarsData::getHero(isset($args['episode']) ? $args['episode'] : null);
|
||||||
|
},
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$mutationType = new ObjectType([
|
||||||
|
'name' => 'Mutation',
|
||||||
|
'fields' => [
|
||||||
|
'createReviewForEpisode' => [
|
||||||
|
'type' => $createReviewForEpisode,
|
||||||
|
'args' => [
|
||||||
|
'episode' => $episodeEnum,
|
||||||
|
'review' => $reviewInputObject
|
||||||
|
],
|
||||||
|
'resolve' => function() {
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep in mind that other than the special meaning of declaring surface area of your API,
|
||||||
|
those types are the same as any other object type, and their fields work exactly the same way.
|
||||||
|
|
||||||
|
Resolvers of those fields receive `$rootValue` which you pass into execute call:
|
||||||
|
`GraphQL::execute($schema, $query, $rootValue)`
|
||||||
|
|
||||||
|
`Mutation` type is also just a regular object type. The difference is in semantics.
|
||||||
|
Field names of Mutation type are usually verbs and they almost always have arguments - quite often
|
||||||
|
with complex input values (see [Input Types](input-types/) for details).
|
@ -11,8 +11,8 @@ pages:
|
|||||||
- Interfaces: type-system/interfaces.md
|
- Interfaces: type-system/interfaces.md
|
||||||
- Unions: type-system/unions.md
|
- Unions: type-system/unions.md
|
||||||
- Input Types: type-system/input-types.md
|
- Input Types: type-system/input-types.md
|
||||||
|
- Directives: type-system/directives.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…
Reference in New Issue
Block a user