mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-21 20:36:05 +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
|
||||
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
|
||||
- Unions: type-system/unions.md
|
||||
- Input Types: type-system/input-types.md
|
||||
- Directives: type-system/directives.md
|
||||
- Defining Schema: type-system/schema.md
|
||||
- Custom Metadata: type-system/metadata.md
|
||||
- Data Fetching: data-fetching.md
|
||||
- Best Practices: best-practices.md
|
||||
- Complementary Tools: complementary-tools.md
|
||||
|
Loading…
Reference in New Issue
Block a user