Work in progress on better docs (added sections on directives and schema to docs)

This commit is contained in:
vladar 2016-11-08 17:17:48 +07:00
parent add2621a33
commit 24b2285ffe
5 changed files with 161 additions and 1 deletions

View 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`

View File

@ -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.

View File

@ -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).

View File

@ -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