mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-21 20:36:05 +03:00
Documentation improvements
This commit is contained in:
parent
de791536ce
commit
7f346d5658
@ -146,6 +146,8 @@ It requires promise adapter in it's first argument and always returns a `Promise
|
|||||||
Old methods `GraphQL::execute` and `GraphQL::executeAndReturnResult` still work in backwards-compatible manner,
|
Old methods `GraphQL::execute` and `GraphQL::executeAndReturnResult` still work in backwards-compatible manner,
|
||||||
but they are deprecated and will be removed eventually.
|
but they are deprecated and will be removed eventually.
|
||||||
|
|
||||||
|
Same applies to Executor: use `Executor::promiseToExecute()` vs `Executor::execute()`.
|
||||||
|
|
||||||
## Upgrade v0.7.x > v0.8.x
|
## Upgrade v0.7.x > v0.8.x
|
||||||
All of those changes apply to those who extends various parts of this library.
|
All of those changes apply to those who extends various parts of this library.
|
||||||
If you only use the library and don't try to extend it - everything should work without breaks.
|
If you only use the library and don't try to extend it - everything should work without breaks.
|
||||||
|
@ -11,3 +11,4 @@
|
|||||||
- [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij)
|
- [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij)
|
||||||
or [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp) -
|
or [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp) -
|
||||||
GraphiQL as Google Chrome extension
|
GraphiQL as Google Chrome extension
|
||||||
|
- [DataLoader PHP](https://github.com/overblog/dataloader-php) - as a ready implementation for [deferred resolvers](data-fetching.md#solving-n1-problem)
|
@ -2,11 +2,11 @@
|
|||||||
GraphQL is data-storage agnostic. You can use any underlying data storage engine, including SQL or NoSQL database,
|
GraphQL is data-storage agnostic. You can use any underlying data storage engine, including SQL or NoSQL database,
|
||||||
plain files or in-memory data structures.
|
plain files or in-memory data structures.
|
||||||
|
|
||||||
In order to convert GraphQL query to PHP array **graphql-php** traverses query fields (using depth-first algorithm) and
|
In order to convert the GraphQL query to PHP array, **graphql-php** traverses query fields (using depth-first algorithm) and
|
||||||
runs special **resolve** function on each field. This **resolve** function is provided by you as a part of
|
runs special **resolve** function on each field. This **resolve** function is provided by you as a part of
|
||||||
[field definition](type-system/object-types.md#field-configuration-options) or [query execution call](executing-queries.md#overview).
|
[field definition](type-system/object-types.md#field-configuration-options) or [query execution call](executing-queries.md#overview).
|
||||||
|
|
||||||
Result returned by **resolve** function is directly included in response (for scalars and enums)
|
Result returned by **resolve** function is directly included in the response (for scalars and enums)
|
||||||
or passed down to nested fields (for objects).
|
or passed down to nested fields (for objects).
|
||||||
|
|
||||||
Let's walk through an example. Consider following GraphQL query:
|
Let's walk through an example. Consider following GraphQL query:
|
||||||
@ -25,6 +25,9 @@ Let's walk through an example. Consider following GraphQL query:
|
|||||||
We need a Schema that can fulfill it. On the very top level the Schema contains Query type:
|
We need a Schema that can fulfill it. On the very top level the Schema contains Query type:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
$queryType = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -46,12 +49,16 @@ $queryType = new ObjectType([
|
|||||||
|
|
||||||
As we see field **lastStory** has **resolve** function that is responsible for fetching data.
|
As we see field **lastStory** has **resolve** function that is responsible for fetching data.
|
||||||
|
|
||||||
In our example we simply return array value, but in real-world application you would query
|
In our example, we simply return array value, but in the real-world application you would query
|
||||||
your database/cache/search index and return result.
|
your database/cache/search index and return the result.
|
||||||
|
|
||||||
Since **lastStory** is of composite type **BlogStory** this result is passed down to fields of this type:
|
Since **lastStory** is of composite type **BlogStory** this result is passed down to fields of this type:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$blogStoryType = new ObjectType([
|
$blogStoryType = new ObjectType([
|
||||||
'name' => 'BlogStory',
|
'name' => 'BlogStory',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -83,8 +90,8 @@ $blogStoryType = new ObjectType([
|
|||||||
|
|
||||||
Here **$blogStory** is the array returned by **lastStory** field above.
|
Here **$blogStory** is the array returned by **lastStory** field above.
|
||||||
|
|
||||||
Again: in real-world applications you would fetch user data from datastore by **authorId** and return it.
|
Again: in the real-world applications you would fetch user data from data store by **authorId** and return it.
|
||||||
Also note that you don't have to return arrays. You can return any value, **graphql-php** will pass it untouched
|
Also, note that you don't have to return arrays. You can return any value, **graphql-php** will pass it untouched
|
||||||
to nested resolvers.
|
to nested resolvers.
|
||||||
|
|
||||||
But then the question appears - field **title** has no **resolve** option. How is it resolved?
|
But then the question appears - field **title** has no **resolve** option. How is it resolved?
|
||||||
@ -95,7 +102,8 @@ for a field you simply override this default resolver.
|
|||||||
# Default Field Resolver
|
# Default Field Resolver
|
||||||
**graphql-php** provides following default field resolver:
|
**graphql-php** provides following default field resolver:
|
||||||
```php
|
```php
|
||||||
function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
|
<?php
|
||||||
|
function defaultFieldResolver($source, $args, $context, \GraphQL\Type\Definition\ResolveInfo $info)
|
||||||
{
|
{
|
||||||
$fieldName = $info->fieldName;
|
$fieldName = $info->fieldName;
|
||||||
$property = null;
|
$property = null;
|
||||||
@ -115,7 +123,7 @@ function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
|
|||||||
```
|
```
|
||||||
|
|
||||||
As you see it returns value by key (for arrays) or property (for objects).
|
As you see it returns value by key (for arrays) or property (for objects).
|
||||||
If value is not set - it returns **null**.
|
If the value is not set - it returns **null**.
|
||||||
|
|
||||||
To override the default resolver, pass it as an argument of [executeQuery](executing-queries.md) call.
|
To override the default resolver, pass it as an argument of [executeQuery](executing-queries.md) call.
|
||||||
|
|
||||||
@ -124,6 +132,11 @@ Sometimes it might be convenient to set default field resolver per type. You can
|
|||||||
[resolveField option in type config](type-system/object-types.md#configuration-options). For example:
|
[resolveField option in type config](type-system/object-types.md#configuration-options). For example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
|
|
||||||
$userType = new ObjectType([
|
$userType = new ObjectType([
|
||||||
'name' => 'User',
|
'name' => 'User',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -167,13 +180,14 @@ Consider following GraphQL query:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Naive field resolution process would require up to 10 calls to underlying data store to fetch authors for all 10 stories.
|
Naive field resolution process would require up to 10 calls to the underlying data store to fetch authors for all 10 stories.
|
||||||
|
|
||||||
**graphql-php** provides tools to mitigate this problem: it allows you to defer actual field resolution to later stage
|
**graphql-php** provides tools to mitigate this problem: it allows you to defer actual field resolution to a later stage
|
||||||
when one batched query could be executed instead of 10 distinct queries.
|
when one batched query could be executed instead of 10 distinct queries.
|
||||||
|
|
||||||
Here is an example of `BlogStory` resolver for field `author` that uses deferring:
|
Here is an example of **BlogStory** resolver for field **author** that uses deferring:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
'resolve' => function($blogStory) {
|
'resolve' => function($blogStory) {
|
||||||
MyUserBuffer::add($blogStory['authorId']);
|
MyUserBuffer::add($blogStory['authorId']);
|
||||||
|
|
||||||
@ -184,18 +198,16 @@ Here is an example of `BlogStory` resolver for field `author` that uses deferrin
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example we fill up buffer with 10 author ids first. Then **graphql-php** continues
|
In this example, we fill up the buffer with 10 author ids first. Then **graphql-php** continues
|
||||||
resolving other non-deferred fields until there are none of them left.
|
resolving other non-deferred fields until there are none of them left.
|
||||||
|
|
||||||
After that it calls `Closures` wrapped by `GraphQL\Deferred` which in turn load all buffered
|
After that, it calls closures wrapped by `GraphQL\Deferred` which in turn load all buffered
|
||||||
ids once (using SQL IN(?), Redis MGET or other similar tools) and return final field value.
|
ids once (using SQL IN(?), Redis MGET or other similar tools) and returns final field value.
|
||||||
|
|
||||||
Originally this approach was advocated by Facebook in their [Dataloader](https://github.com/facebook/dataloader)
|
Originally this approach was advocated by Facebook in their [Dataloader](https://github.com/facebook/dataloader)
|
||||||
project.
|
project. This solution enables very interesting optimizations at no cost. Consider the following query:
|
||||||
|
|
||||||
This solution enables very interesting optimizations at no cost. Consider following query:
|
```graphql
|
||||||
|
|
||||||
```
|
|
||||||
{
|
{
|
||||||
topStories(limit: 10) {
|
topStories(limit: 10) {
|
||||||
author {
|
author {
|
||||||
@ -212,14 +224,14 @@ This solution enables very interesting optimizations at no cost. Consider follow
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Even if `author` field is located on different levels of query - it can be buffered in the same buffer.
|
Even though **author** field is located on different levels of the query - it can be buffered in the same buffer.
|
||||||
In this example only one query will be executed for all story authors comparing to 20 queries
|
In this example, only one query will be executed for all story authors comparing to 20 queries
|
||||||
in naive implementation.
|
in a naive implementation.
|
||||||
|
|
||||||
# Async PHP
|
# Async PHP
|
||||||
Since: 0.10.0 (version 0.9.0 had slightly different API which is deprecated)
|
Since: 0.10.0 (version 0.9.0 had slightly different API which still works, but is deprecated)
|
||||||
|
|
||||||
If your project runs in environment that supports async operations
|
If your project runs in an environment that supports async operations
|
||||||
(like HHVM, ReactPHP, Icicle.io, appserver.io, PHP threads, etc)
|
(like HHVM, ReactPHP, Icicle.io, appserver.io, PHP threads, etc)
|
||||||
you can leverage the power of your platform to resolve some fields asynchronously.
|
you can leverage the power of your platform to resolve some fields asynchronously.
|
||||||
|
|
||||||
@ -230,6 +242,10 @@ To start using this feature, switch facade method for query execution from
|
|||||||
**executeQuery** to **promiseToExecute**:
|
**executeQuery** to **promiseToExecute**:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\GraphQL;
|
||||||
|
use GraphQL\Executor\ExecutionResult;
|
||||||
|
|
||||||
$promise = GraphQL::promiseToExecute(
|
$promise = GraphQL::promiseToExecute(
|
||||||
$promiseAdapter,
|
$promiseAdapter,
|
||||||
$schema,
|
$schema,
|
||||||
@ -252,6 +268,6 @@ Where **$promiseAdapter** is an instance of:
|
|||||||
`GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter`
|
`GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter`
|
||||||
|
|
||||||
* Other platforms: write your own class implementing interface: <br>
|
* Other platforms: write your own class implementing interface: <br>
|
||||||
`GraphQL\Executor\Promise\PromiseAdapter`.
|
[`GraphQL\Executor\Promise\PromiseAdapter`](reference.md#graphqlexecutorpromisepromiseadapter).
|
||||||
|
|
||||||
Then your **resolve** functions should return promises of your platform instead of `GraphQL\Deferred`s.
|
Then your **resolve** functions should return promises of your platform instead of `GraphQL\Deferred`s.
|
@ -1,47 +1,52 @@
|
|||||||
# Errors in GraphQL
|
# Errors in GraphQL
|
||||||
|
|
||||||
Query execution process never throws exceptions. Instead all errors are caught and collected in
|
Query execution process never throws exceptions. Instead, all errors are caught and collected.
|
||||||
[execution result](executing-queries.md#execution-result).
|
After execution, they are available in **$errors** prop of
|
||||||
|
[`GraphQL\Executor\ExecutionResult`](reference.md#graphqlexecutorexecutionresult).
|
||||||
|
|
||||||
Later `$result->toArray()` automatically converts these errors to array using default
|
When the result is converted to a serializable array using its **toArray()** method, all errors are
|
||||||
error formatting. But you can apply [custom error filtering and formatting](#custom-error-filtering-and-formatting)
|
converted to arrays as well using default error formatting (see below).
|
||||||
|
|
||||||
|
Alternatively, you can apply [custom error filtering and formatting](#custom-error-handling-and-formatting)
|
||||||
for your specific requirements.
|
for your specific requirements.
|
||||||
|
|
||||||
# Default Error formatting
|
# Default Error formatting
|
||||||
By default each error entry is converted to associative array with following structure:
|
By default, each error entry is converted to an associative array with following structure:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
[
|
[
|
||||||
'message' => 'Error message',
|
'message' => 'Error message',
|
||||||
'category' => 'graphql',
|
'category' => 'graphql',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
['line' => 1, 'column' => 2]
|
['line' => 1, 'column' => 2]
|
||||||
],
|
],
|
||||||
'path': [
|
'path' => [
|
||||||
'listField',
|
'listField',
|
||||||
0,
|
0,
|
||||||
'fieldWithException'
|
'fieldWithException'
|
||||||
]
|
]
|
||||||
]
|
];
|
||||||
```
|
```
|
||||||
Entry at key **locations** points to character in query string which caused the error.
|
Entry at key **locations** points to a character in query string which caused the error.
|
||||||
In some cases (like deep fragment fields) locations will include several entries to track down path to
|
In some cases (like deep fragment fields) locations will include several entries to track down
|
||||||
field with error in query.
|
the path to field with the error in query.
|
||||||
|
|
||||||
Entry at key **path** exists only for errors caused by exceptions thrown in resolvers. It contains path
|
Entry at key **path** exists only for errors caused by exceptions thrown in resolvers.
|
||||||
from the very root field to actual field value producing an error
|
It contains a path from the very root field to actual field value producing an error
|
||||||
(including indexes for list types and field names for composite types).
|
(including indexes for list types and field names for composite types).
|
||||||
|
|
||||||
**Internal errors**
|
**Internal errors**
|
||||||
|
|
||||||
As of version **0.10.0** all exceptions thrown in resolvers are reported with generic message **"Internal server error"**.
|
As of version **0.10.0**, all exceptions thrown in resolvers are reported with generic message **"Internal server error"**.
|
||||||
This is done to avoid information leak in production environments (e.g. database connection errors, file access errors, etc).
|
This is done to avoid information leak in production environments (e.g. database connection errors, file access errors, etc).
|
||||||
|
|
||||||
Only exceptions implementing interface `GraphQL\Error\ClientAware` and claiming themselves as **safe** will
|
Only exceptions implementing interface [`GraphQL\Error\ClientAware`](reference.md#graphqlerrorclientaware) and claiming themselves as **safe** will
|
||||||
be reported with full error message.
|
be reported with a full error message.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Error\ClientAware;
|
use GraphQL\Error\ClientAware;
|
||||||
|
|
||||||
class MySafeException extends \Exception implements ClientAware
|
class MySafeException extends \Exception implements ClientAware
|
||||||
@ -57,20 +62,21 @@ class MySafeException extends \Exception implements ClientAware
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
When such exception is thrown it will be reported with full error message:
|
When such exception is thrown it will be reported with a full error message:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
[
|
[
|
||||||
'message' => 'My reported error',
|
'message' => 'My reported error',
|
||||||
'category' => 'businessLogic',
|
'category' => 'businessLogic',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
['line' => 10, 'column' => 2]
|
['line' => 10, 'column' => 2]
|
||||||
],
|
],
|
||||||
'path': [
|
'path' => [
|
||||||
'path',
|
'path',
|
||||||
'to',
|
'to',
|
||||||
'fieldWithException'
|
'fieldWithException'
|
||||||
]
|
]
|
||||||
]
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
To change default **"Internal server error"** message to something else, use:
|
To change default **"Internal server error"** message to something else, use:
|
||||||
@ -91,6 +97,7 @@ $result = GraphQL::executeQuery(/*args*/)->toArray($debug);
|
|||||||
|
|
||||||
This will make each error entry to look like this:
|
This will make each error entry to look like this:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
[
|
[
|
||||||
'debugMessage' => 'Actual exception message',
|
'debugMessage' => 'Actual exception message',
|
||||||
'message' => 'Internal server error',
|
'message' => 'Internal server error',
|
||||||
@ -98,7 +105,7 @@ This will make each error entry to look like this:
|
|||||||
'locations' => [
|
'locations' => [
|
||||||
['line' => 10, 'column' => 2]
|
['line' => 10, 'column' => 2]
|
||||||
],
|
],
|
||||||
'path': [
|
'path' => [
|
||||||
'listField',
|
'listField',
|
||||||
0,
|
0,
|
||||||
'fieldWithException'
|
'fieldWithException'
|
||||||
@ -106,11 +113,13 @@ This will make each error entry to look like this:
|
|||||||
'trace' => [
|
'trace' => [
|
||||||
/* Formatted original exception trace */
|
/* Formatted original exception trace */
|
||||||
]
|
]
|
||||||
]
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
If you prefer first resolver exception to be re-thrown, use following flags:
|
If you prefer first resolver exception to be re-thrown, use following flags:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Error\Debug;
|
use GraphQL\Error\Debug;
|
||||||
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::RETHROW_INTERNAL_EXCEPTIONS;
|
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::RETHROW_INTERNAL_EXCEPTIONS;
|
||||||
|
|
||||||
@ -121,12 +130,14 @@ $result = GraphQL::executeQuery(/*args*/)->toArray($debug);
|
|||||||
# Custom Error Handling and Formatting
|
# Custom Error Handling and Formatting
|
||||||
It is possible to define custom **formatter** and **handler** for result errors.
|
It is possible to define custom **formatter** and **handler** for result errors.
|
||||||
|
|
||||||
**Formatter** is responsible for converting instances of `GraphQL\Error\Error` to array.
|
**Formatter** is responsible for converting instances of [`GraphQL\Error\Error`](reference.md#graphqlerrorerror)
|
||||||
**Handler** is useful for error filtering and logging.
|
to an array. **Handler** is useful for error filtering and logging.
|
||||||
|
|
||||||
For example these are default formatter and handler:
|
For example, these are default formatter and handler:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\GraphQL;
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Error\FormattedError;
|
use GraphQL\Error\FormattedError;
|
||||||
|
|
||||||
@ -144,7 +155,7 @@ $result = GraphQL::executeQuery(/* $args */)
|
|||||||
->toArray();
|
->toArray();
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that when you pass [debug flags](#debugging-tools) to `toArray()` your custom formatter will still be
|
Note that when you pass [debug flags](#debugging-tools) to **toArray()** your custom formatter will still be
|
||||||
decorated with same debugging information mentioned above.
|
decorated with same debugging information mentioned above.
|
||||||
|
|
||||||
# Schema Errors
|
# Schema Errors
|
||||||
@ -155,6 +166,11 @@ Usually such errors mean that there is some logical error in your schema and it
|
|||||||
when it makes sense to return `500` error code for GraphQL endpoint:
|
when it makes sense to return `500` error code for GraphQL endpoint:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\GraphQL;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
|
use GraphQL\Error\FormattedError;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
// ...
|
// ...
|
||||||
@ -163,9 +179,9 @@ try {
|
|||||||
$body = GraphQL::executeQuery($schema, $query);
|
$body = GraphQL::executeQuery($schema, $query);
|
||||||
$status = 200;
|
$status = 200;
|
||||||
} catch(\Exception $e) {
|
} catch(\Exception $e) {
|
||||||
$body = json_encode([
|
$body = [
|
||||||
'message' => 'Unexpected error'
|
'errors' => [FormattedError::createFromException($e)]
|
||||||
]);
|
];
|
||||||
$status = 500;
|
$status = 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@
|
|||||||
Query execution is a complex process involving multiple steps, including query **parsing**,
|
Query execution is a complex process involving multiple steps, including query **parsing**,
|
||||||
**validating** and finally **executing** against your [schema](type-system/schema.md).
|
**validating** and finally **executing** against your [schema](type-system/schema.md).
|
||||||
|
|
||||||
**graphql-php** provides convenient facade for this process in class
|
**graphql-php** provides a convenient facade for this process in class
|
||||||
[`GraphQL\GraphQL`](reference.md#graphqlgraphql):
|
[`GraphQL\GraphQL`](reference.md#graphqlgraphql):
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\GraphQL;
|
use GraphQL\GraphQL;
|
||||||
|
|
||||||
$result = GraphQL::executeQuery(
|
$result = GraphQL::executeQuery(
|
||||||
@ -27,28 +28,28 @@ which can be easily converted to array:
|
|||||||
$serializableResult = $result->toArray();
|
$serializableResult = $result->toArray();
|
||||||
```
|
```
|
||||||
|
|
||||||
Returned array contains **data** and **errors** keys, as described by
|
Returned array contains **data** and **errors** keys, as described by the
|
||||||
[GraphQL spec](http://facebook.github.io/graphql/#sec-Response-Format).
|
[GraphQL spec](http://facebook.github.io/graphql/#sec-Response-Format).
|
||||||
This array is suitable for further serialization (e.g. using **json_encode**).
|
This array is suitable for further serialization (e.g. using **json_encode**).
|
||||||
See also section on [error handling and formatting](error-handling.md).
|
See also the section on [error handling and formatting](error-handling.md).
|
||||||
|
|
||||||
Description of **executeQuery** method arguments:
|
Description of **executeQuery** method arguments:
|
||||||
|
|
||||||
Argument | Type | Notes
|
Argument | Type | Notes
|
||||||
------------ | -------- | -----
|
------------ | -------- | -----
|
||||||
schema | [`GraphQL\Type\Schema`](#) | **Required.** Instance of your application [Schema](type-system/schema.md)
|
schema | [`GraphQL\Type\Schema`](#) | **Required.** Instance of your application [Schema](type-system/schema.md)
|
||||||
queryString | `string` or `GraphQL\Language\AST\DocumentNode` | **Required.** Actual GraphQL query string to be parsed, validated and executed. If you parse query elsewhere before executing - pass corresponding ast document here to avoid new parsing.
|
queryString | `string` or `GraphQL\Language\AST\DocumentNode` | **Required.** Actual GraphQL query string to be parsed, validated and executed. If you parse query elsewhere before executing - pass corresponding AST document here to avoid new parsing.
|
||||||
rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself.
|
rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself.
|
||||||
context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.<br><br>It will be available as 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers.
|
context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.<br><br>It will be available as the 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers.
|
||||||
variableValues | `array` | Map of variable values passed along with query string. See section on [query variables on official GraphQL website](http://graphql.org/learn/queries/#variables)
|
variableValues | `array` | Map of variable values passed along with query string. See section on [query variables on official GraphQL website](http://graphql.org/learn/queries/#variables)
|
||||||
operationName | `string` | Allows the caller to specify which operation in queryString will be run, in cases where queryString contains multiple top-level operations.
|
operationName | `string` | Allows the caller to specify which operation in queryString will be run, in cases where queryString contains multiple top-level operations.
|
||||||
fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver).
|
fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver).
|
||||||
validationRules | `array` | A set of rules for query validation step. Default value is all available rules. Empty array would allow to skip query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution)
|
validationRules | `array` | A set of rules for query validation step. The default value is all available rules. Empty array would allow skipping query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution)
|
||||||
|
|
||||||
# Using Server
|
# Using Server
|
||||||
If you are building HTTP GraphQL API, you may prefer our Standard Server
|
If you are building HTTP GraphQL API, you may prefer our Standard Server
|
||||||
(compatible with [express-graphql](https://github.com/graphql/express-graphql)).
|
(compatible with [express-graphql](https://github.com/graphql/express-graphql)).
|
||||||
It supports more features out of the box, including parsing HTTP requests, producing spec-compliant response; [batched queries](#query-batching); persisted queries.
|
It supports more features out of the box, including parsing HTTP requests, producing a spec-compliant response; [batched queries](#query-batching); persisted queries.
|
||||||
|
|
||||||
Usage example (with plain PHP):
|
Usage example (with plain PHP):
|
||||||
|
|
||||||
@ -88,20 +89,20 @@ PSR-7 is useful when you want to integrate the server into existing framework:
|
|||||||
- [PSR-7 for Laravel](https://laravel.com/docs/5.1/requests#psr7-requests)
|
- [PSR-7 for Laravel](https://laravel.com/docs/5.1/requests#psr7-requests)
|
||||||
- [Symfony PSR-7 Bridge](https://symfony.com/doc/current/request/psr7.html)
|
- [Symfony PSR-7 Bridge](https://symfony.com/doc/current/request/psr7.html)
|
||||||
- [Slim](https://www.slimframework.com/docs/concepts/value-objects.html)
|
- [Slim](https://www.slimframework.com/docs/concepts/value-objects.html)
|
||||||
- [Zend Diactoros](https://zendframework.github.io/zend-diactoros/)
|
- [Zend Expressive](http://zendframework.github.io/zend-expressive/)
|
||||||
|
|
||||||
## Server configuration options
|
## Server configuration options
|
||||||
|
|
||||||
Argument | Type | Notes
|
Argument | Type | Notes
|
||||||
------------ | -------- | -----
|
------------ | -------- | -----
|
||||||
schema | [`Schema`](reference.md#graphqltypeschema) | **Required.** Instance of your application [Schema](type-system/schema/)
|
schema | [`Schema`](reference.md#graphqltypeschema) | **Required.** Instance of your application [Schema](type-system/schema/)
|
||||||
rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself.
|
rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself.
|
||||||
context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.<br><br>It will be available as 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers.
|
context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.<br><br>It will be available as the 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers.
|
||||||
fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver).
|
fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver).
|
||||||
validationRules | `array` or `callable` | A set of rules for query validation step. Default value is all available rules. Empty array would allow to skip query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution).<br><br>Pass `callable` to return different validation rules for different queries (e.g. empty array for persisted query and full list of rules for regular queries). When passed, it is expected to have following signature: <br><br> **function (OperationParams $params, DocumentNode $node, $operationType): array** <br><br> See also docs on [OperationParams](reference.md#graphqlserveroperationparams).
|
validationRules | `array` or `callable` | A set of rules for query validation step. The default value is all available rules. The empty array would allow skipping query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution).<br><br>Pass `callable` to return different validation rules for different queries (e.g. empty array for persisted query and a full list of rules for regular queries). When passed, it is expected to have the following signature: <br><br> **function ([OperationParams](reference.md#graphqlserveroperationparams) $params, DocumentNode $node, $operationType): array**
|
||||||
queryBatching | `bool` | Flag indicating whether this server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)).<br><br> Defaults to **false**
|
queryBatching | `bool` | Flag indicating whether this server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)).<br><br> Defaults to **false**
|
||||||
debug | `int` | Debug flags. See [docs on error debugging](error-handling.md#debugging-tools) (flag values are the same).
|
debug | `int` | Debug flags. See [docs on error debugging](error-handling.md#debugging-tools) (flag values are the same).
|
||||||
persistentQueryLoader | `callable` | Function which is called to fetch actual query when server encounters **queryId** in request vs **query**.<br><br> Server does not implement persistence part (which you will have to build on your own), but it allows you to execute queries which were persisted previously.<br><br> Expected function signature:<br> **function ($queryId, OperationParams $params)** <br><br>Function is expected to return query **string** or parsed **DocumentNode** <br><br> See also docs on [OperationParams](reference.md#graphqlserveroperationparams). <br><br> [Read more about persisted queries](https://dev-blog.apollodata.com/persisted-graphql-queries-with-apollo-client-119fd7e6bba5).
|
persistentQueryLoader | `callable` | A function which is called to fetch actual query when server encounters **queryId** in request vs **query**.<br><br> The server does not implement persistence part (which you will have to build on your own), but it allows you to execute queries which were persisted previously.<br><br> Expected function signature:<br> **function ($queryId, [OperationParams](reference.md#graphqlserveroperationparams) $params)** <br><br>Function is expected to return query **string** or parsed **DocumentNode** <br><br> [Read more about persisted queries](https://dev-blog.apollodata.com/persisted-graphql-queries-with-apollo-client-119fd7e6bba5).
|
||||||
errorFormatter | `callable` | Custom error formatter. See [error handling docs](error-handling.md#custom-error-handling-and-formatting).
|
errorFormatter | `callable` | Custom error formatter. See [error handling docs](error-handling.md#custom-error-handling-and-formatting).
|
||||||
errorsHandler | `callable` | Custom errors handler. See [error handling docs](error-handling.md#custom-error-handling-and-formatting).
|
errorsHandler | `callable` | Custom errors handler. See [error handling docs](error-handling.md#custom-error-handling-and-formatting).
|
||||||
promiseAdapter | [`PromiseAdapter`](reference.md#graphqlexecutorpromisepromiseadapter) | Required for [Async PHP](data-fetching/#async-php) only.
|
promiseAdapter | [`PromiseAdapter`](reference.md#graphqlexecutorpromisepromiseadapter) | Required for [Async PHP](data-fetching/#async-php) only.
|
||||||
@ -109,7 +110,7 @@ promiseAdapter | [`PromiseAdapter`](reference.md#graphqlexecutorpromisepromisead
|
|||||||
**Server config instance**
|
**Server config instance**
|
||||||
|
|
||||||
If you prefer fluid interface for config with autocomplete in IDE and static time validation,
|
If you prefer fluid interface for config with autocomplete in IDE and static time validation,
|
||||||
use `GraphQL\Server\ServerConfig` instead of an array:
|
use [`GraphQL\Server\ServerConfig`](reference.md#graphqlserverserverconfig) instead of an array:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
@ -128,9 +129,8 @@ $server = new StandardServer($config);
|
|||||||
## Query batching
|
## Query batching
|
||||||
Standard Server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)).
|
Standard Server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)).
|
||||||
|
|
||||||
One of the major benefits of Server over sequence of **executeQuery()** calls is that
|
One of the major benefits of Server over a sequence of **executeQuery()** calls is that
|
||||||
[Deferred resolvers](data-fetching.md#solving-n1-problem) won't be isolated in queries.
|
[Deferred resolvers](data-fetching.md#solving-n1-problem) won't be isolated in queries.
|
||||||
|
|
||||||
So for example following batch will require single DB request (if user field is deferred):
|
So for example following batch will require single DB request (if user field is deferred):
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -158,7 +158,7 @@ $server = new StandardServer([
|
|||||||
```
|
```
|
||||||
|
|
||||||
# Custom Validation Rules
|
# Custom Validation Rules
|
||||||
Before execution, query is validated using set of standard rules defined by GraphQL spec.
|
Before execution, a query is validated using a set of standard rules defined by the GraphQL spec.
|
||||||
It is possible to override standard set of rules globally or per execution.
|
It is possible to override standard set of rules globally or per execution.
|
||||||
|
|
||||||
Add rules globally:
|
Add rules globally:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Prerequisites
|
# Prerequisites
|
||||||
This documentation assumes your familiarity with GraphQL concepts. If it is not the case -
|
This documentation assumes your familiarity with GraphQL concepts. If it is not the case -
|
||||||
first learn about GraphQL on [official website](http://graphql.org/learn/).
|
first learn about GraphQL on [the official website](http://graphql.org/learn/).
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ they are explained in [upgrade instructions](https://github.com/webonyx/graphql-
|
|||||||
# Install Tools (optional)
|
# Install Tools (optional)
|
||||||
While it is possible to communicate with GraphQL API using regular HTTP tools it is way
|
While it is possible to communicate with GraphQL API using regular HTTP tools it is way
|
||||||
more convenient for humans to use [GraphiQL](https://github.com/graphql/graphiql) - an in-browser
|
more convenient for humans to use [GraphiQL](https://github.com/graphql/graphiql) - an in-browser
|
||||||
ide for exploring GraphQL APIs.
|
IDE for exploring GraphQL APIs.
|
||||||
|
|
||||||
It provides syntax-highlighting, auto-completion and auto-generated documentation for
|
It provides syntax-highlighting, auto-completion and auto-generated documentation for
|
||||||
GraphQL API.
|
GraphQL API.
|
||||||
@ -27,12 +27,12 @@ The easiest way to use it is to install one of the existing Google Chrome extens
|
|||||||
- [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij)
|
- [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij)
|
||||||
- [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp)
|
- [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp)
|
||||||
|
|
||||||
Alternatively you can follow instructions on [GraphiQL](https://github.com/graphql/graphiql)
|
Alternatively, you can follow instructions on [the GraphiQL](https://github.com/graphql/graphiql)
|
||||||
page and install it locally.
|
page and install it locally.
|
||||||
|
|
||||||
|
|
||||||
# Hello World
|
# Hello World
|
||||||
Let's create type system that will be capable to process following simple query:
|
Let's create a type system that will be capable to process following simple query:
|
||||||
```
|
```
|
||||||
query {
|
query {
|
||||||
echo(message: "Hello World")
|
echo(message: "Hello World")
|
||||||
@ -66,7 +66,7 @@ $queryType = new ObjectType([
|
|||||||
(Note: type definition can be expressed in [different styles](type-system/index.md#type-definition-styles),
|
(Note: type definition can be expressed in [different styles](type-system/index.md#type-definition-styles),
|
||||||
but this example uses **inline** style for simplicity)
|
but this example uses **inline** style for simplicity)
|
||||||
|
|
||||||
The interesting piece here is `resolve` option of field definition. It is responsible for retuning
|
The interesting piece here is **resolve** option of field definition. It is responsible for returning
|
||||||
a value of our field. Values of **scalar** fields will be directly included in response while values of
|
a value of our field. Values of **scalar** fields will be directly included in response while values of
|
||||||
**composite** fields (objects, interfaces, unions) will be passed down to nested field resolvers
|
**composite** fields (objects, interfaces, unions) will be passed down to nested field resolvers
|
||||||
(not in this example though).
|
(not in this example though).
|
||||||
@ -118,7 +118,7 @@ So check out next example, which is closer to real-world apps.
|
|||||||
Or keep reading about [schema definition](type-system/index.md).
|
Or keep reading about [schema definition](type-system/index.md).
|
||||||
|
|
||||||
# Blog example
|
# Blog example
|
||||||
It is often easier to start with full-featured example and then get back to documentation
|
It is often easier to start with a full-featured example and then get back to documentation
|
||||||
for your own work.
|
for your own work.
|
||||||
|
|
||||||
Check out [Blog example of GraphQL API](https://github.com/webonyx/graphql-php/tree/master/examples/01-blog).
|
Check out [Blog example of GraphQL API](https://github.com/webonyx/graphql-php/tree/master/examples/01-blog).
|
||||||
|
@ -19,16 +19,17 @@ There are 3 types of errors in GraphQL:
|
|||||||
- **Validation**: query is incompatible with type system (e.g. unknown field is requested);
|
- **Validation**: query is incompatible with type system (e.g. unknown field is requested);
|
||||||
- **Execution**: occurs when some field resolver throws (or returns unexpected value).
|
- **Execution**: occurs when some field resolver throws (or returns unexpected value).
|
||||||
|
|
||||||
Obviously when **Syntax** or **Validation** error is detected - process is interrupted and query is not
|
Obviously, when **Syntax** or **Validation** error is detected - the process is interrupted and
|
||||||
executed.
|
the query is not executed.
|
||||||
|
|
||||||
Execution process never throws exceptions. Instead all errors are caught and collected in
|
Execution process never throws exceptions. Instead, all errors are caught and collected in
|
||||||
execution result.
|
execution result.
|
||||||
|
|
||||||
GraphQL is forgiving to **Execution** errors which occur in resolvers of nullable fields.
|
GraphQL is forgiving to **Execution** errors which occur in resolvers of nullable fields.
|
||||||
If such field throws or returns unexpected value the value of the field in response will be simply
|
If such field throws or returns unexpected value the value of the field in response will be simply
|
||||||
replaced with `null` and error entry will be registered.
|
replaced with **null** and error entry will be registered.
|
||||||
|
|
||||||
If exception is thrown in non-null field - error bubbles up to first nullable field. This nullable
|
If an exception is thrown in the non-null field - error bubbles up to the first nullable field.
|
||||||
field is replaced with `null` and error entry is added to response. If all fields up to the root are
|
This nullable field is replaced with **null** and error entry is added to the result.
|
||||||
non-null - **data** entry will be removed from response and only **errors** key will be presented.
|
If all fields up to the root are non-null - **data** entry will be removed from the result
|
||||||
|
and only **errors** key will be presented.
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
|
|
||||||
# About GraphQL
|
# About GraphQL
|
||||||
|
|
||||||
GraphQL is a modern way to build HTTP APIs consumed by web and mobile clients.
|
GraphQL is a modern way to build HTTP APIs consumed by the web and mobile clients.
|
||||||
It is intended to be a replacement for REST and SOAP APIs (even for **existing applications**).
|
It is intended to be a replacement for REST and SOAP APIs (even for **existing applications**).
|
||||||
|
|
||||||
GraphQL itself is a [specification](https://github.com/facebook/graphql) designed by Facebook
|
GraphQL itself is a [specification](https://github.com/facebook/graphql) designed by Facebook
|
||||||
engineers. Various implementations of this specification were written
|
engineers. Various implementations of this specification were written
|
||||||
[for different languages and environments](http://graphql.org/code/).
|
[in different languages and environments](http://graphql.org/code/).
|
||||||
|
|
||||||
Great overview of GraphQL features and benefits is presented on [official website](http://graphql.org/).
|
Great overview of GraphQL features and benefits is presented on [the official website](http://graphql.org/).
|
||||||
All of them equally apply to this PHP implementation.
|
All of them equally apply to this PHP implementation.
|
||||||
|
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ published by Facebook.
|
|||||||
|
|
||||||
This library is a thin wrapper around your existing data layer and business logic.
|
This library is a thin wrapper around your existing data layer and business logic.
|
||||||
It doesn't dictate how these layers are implemented or which storage engines
|
It doesn't dictate how these layers are implemented or which storage engines
|
||||||
are used. Instead it provides tools for creating rich API for your existing app.
|
are used. Instead, it provides tools for creating rich API for your existing app.
|
||||||
|
|
||||||
Library features include:
|
Library features include:
|
||||||
|
|
||||||
@ -38,15 +38,16 @@ Library features include:
|
|||||||
- [Async PHP platforms support](data-fetching.md/#async-php) via promises
|
- [Async PHP platforms support](data-fetching.md/#async-php) via promises
|
||||||
- [Standard HTTP server](executing-queries.md/#using-server)
|
- [Standard HTTP server](executing-queries.md/#using-server)
|
||||||
|
|
||||||
Also several [complementary tools](complementary-tools.md) are available which provide integrations with
|
Also, several [complementary tools](complementary-tools.md) are available which provide integrations with
|
||||||
existing PHP frameworks, add support for Relay, etc.
|
existing PHP frameworks, add support for Relay, etc.
|
||||||
|
|
||||||
## Current Status
|
## Current Status
|
||||||
First version of this library (v0.1) was released on August 10th 2015.
|
The first version of this library (v0.1) was released on August 10th 2015.
|
||||||
|
|
||||||
Current version (v0.10) supports all features described by GraphQL specification
|
The current version (v0.10) supports all features described by GraphQL specification
|
||||||
(including April 2016 add-ons) as well as some experimental features like
|
(including April 2016 add-ons) as well as some experimental features like
|
||||||
Schema Language parser.
|
[Schema Language parser](type-system/type-language.md) and
|
||||||
|
[Schema printer](reference.md#graphqlutilsschemaprinter).
|
||||||
|
|
||||||
Ready for real-world usage.
|
Ready for real-world usage.
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ static function float()
|
|||||||
```php
|
```php
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType $wrappedType
|
* @param ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType|ListOfType|NonNull $wrappedType
|
||||||
* @return ListOfType
|
* @return ListOfType
|
||||||
*/
|
*/
|
||||||
static function listOf($wrappedType)
|
static function listOf($wrappedType)
|
||||||
@ -180,7 +180,7 @@ static function listOf($wrappedType)
|
|||||||
```php
|
```php
|
||||||
/**
|
/**
|
||||||
* @api
|
* @api
|
||||||
* @param ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType $wrappedType
|
* @param ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType|ListOfType $wrappedType
|
||||||
* @return NonNull
|
* @return NonNull
|
||||||
*/
|
*/
|
||||||
static function nonNull($wrappedType)
|
static function nonNull($wrappedType)
|
||||||
@ -248,6 +248,157 @@ static function getNullableType($type)
|
|||||||
*/
|
*/
|
||||||
static function getNamedType($type)
|
static function getNamedType($type)
|
||||||
```
|
```
|
||||||
|
# GraphQL\Type\Definition\ResolveInfo
|
||||||
|
Structure containing information useful for field resolution process.
|
||||||
|
Passed as 3rd argument to every field resolver. See [docs on field resolving (data fetching)](data-fetching.md).
|
||||||
|
|
||||||
|
**Class Props:**
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* The name of the field being resolved
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $fieldName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST of all nodes referencing this field in the query.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var FieldNode[]
|
||||||
|
*/
|
||||||
|
public $fieldNodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected return type of the field being resolved
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var ScalarType|ObjectType|InterfaceType|UnionType|EnumType|ListOfType|NonNull
|
||||||
|
*/
|
||||||
|
public $returnType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent type of the field being resolved
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var ObjectType
|
||||||
|
*/
|
||||||
|
public $parentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Path to this field from the very root value
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instance of a schema used for execution
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var Schema
|
||||||
|
*/
|
||||||
|
public $schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST of all fragments defined in query
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var FragmentDefinitionNode[]
|
||||||
|
*/
|
||||||
|
public $fragments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root value passed to query execution
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
public $rootValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST of operation definition node (query, mutation)
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var OperationDefinitionNode
|
||||||
|
*/
|
||||||
|
public $operation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of variables passed to query execution
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $variableValues;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Class Methods:**
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Helper method that returns names of all fields selected in query for
|
||||||
|
* $this->fieldName up to $depth levels
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* query MyQuery{
|
||||||
|
* {
|
||||||
|
* root {
|
||||||
|
* id,
|
||||||
|
* nested {
|
||||||
|
* nested1
|
||||||
|
* nested2 {
|
||||||
|
* nested3
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Given this ResolveInfo instance is a part of "root" field resolution, and $depth === 1,
|
||||||
|
* method will return:
|
||||||
|
* [
|
||||||
|
* 'id' => true,
|
||||||
|
* 'nested' => [
|
||||||
|
* nested1 => true,
|
||||||
|
* nested2 => true
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* Warning: this method it is a naive implementation which does not take into account
|
||||||
|
* conditional typed fragments. So use it with care for fields of interface and union types.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param int $depth How many levels to include in output
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getFieldSelection($depth = 0)
|
||||||
|
```
|
||||||
|
# GraphQL\Type\Definition\DirectiveLocation
|
||||||
|
List of available directive locations
|
||||||
|
|
||||||
|
**Class Constants:**
|
||||||
|
```php
|
||||||
|
const IFACE = "INTERFACE";
|
||||||
|
const SUBSCRIPTION = "SUBSCRIPTION";
|
||||||
|
const FRAGMENT_SPREAD = "FRAGMENT_SPREAD";
|
||||||
|
const QUERY = "QUERY";
|
||||||
|
const MUTATION = "MUTATION";
|
||||||
|
const FRAGMENT_DEFINITION = "FRAGMENT_DEFINITION";
|
||||||
|
const INPUT_OBJECT = "INPUT_OBJECT";
|
||||||
|
const INLINE_FRAGMENT = "INLINE_FRAGMENT";
|
||||||
|
const UNION = "UNION";
|
||||||
|
const SCALAR = "SCALAR";
|
||||||
|
const FIELD_DEFINITION = "FIELD_DEFINITION";
|
||||||
|
const ARGUMENT_DEFINITION = "ARGUMENT_DEFINITION";
|
||||||
|
const ENUM = "ENUM";
|
||||||
|
const OBJECT = "OBJECT";
|
||||||
|
const ENUM_VALUE = "ENUM_VALUE";
|
||||||
|
const FIELD = "FIELD";
|
||||||
|
const SCHEMA = "SCHEMA";
|
||||||
|
const INPUT_FIELD_DEFINITION = "INPUT_FIELD_DEFINITION";
|
||||||
|
```
|
||||||
|
|
||||||
# GraphQL\Type\SchemaConfig
|
# GraphQL\Type\SchemaConfig
|
||||||
Schema configuration class.
|
Schema configuration class.
|
||||||
Could be passed directly to schema constructor. List of options accepted by **create** method is
|
Could be passed directly to schema constructor. List of options accepted by **create** method is
|
||||||
@ -808,7 +959,6 @@ Implements the "Evaluating requests" section of the GraphQL specification.
|
|||||||
* @param array|\ArrayAccess $variableValues
|
* @param array|\ArrayAccess $variableValues
|
||||||
* @param null $operationName
|
* @param null $operationName
|
||||||
* @param callable $fieldResolver
|
* @param callable $fieldResolver
|
||||||
* @param PromiseAdapter $promiseAdapter
|
|
||||||
*
|
*
|
||||||
* @return ExecutionResult|Promise
|
* @return ExecutionResult|Promise
|
||||||
*/
|
*/
|
||||||
@ -819,14 +969,13 @@ static function execute(
|
|||||||
$contextValue = null,
|
$contextValue = null,
|
||||||
$variableValues = null,
|
$variableValues = null,
|
||||||
$operationName = null,
|
$operationName = null,
|
||||||
callable $fieldResolver = null,
|
callable $fieldResolver = null
|
||||||
GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter = null
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
```php
|
```php
|
||||||
/**
|
/**
|
||||||
* Same as executeQuery(), but requires promise adapter and returns a promise which is always
|
* Same as execute(), but requires promise adapter and returns a promise which is always
|
||||||
* fulfilled with an instance of ExecutionResult and never rejected.
|
* fulfilled with an instance of ExecutionResult and never rejected.
|
||||||
*
|
*
|
||||||
* Useful for async PHP platforms.
|
* Useful for async PHP platforms.
|
||||||
@ -1042,132 +1191,6 @@ function createRejected($reason)
|
|||||||
*/
|
*/
|
||||||
function all(array $promisesOrValues)
|
function all(array $promisesOrValues)
|
||||||
```
|
```
|
||||||
# GraphQL\Type\Definition\ResolveInfo
|
|
||||||
Structure containing information useful for field resolution process.
|
|
||||||
Passed as 3rd argument to every field resolver. See [docs on field resolving (data fetching)](data-fetching.md).
|
|
||||||
|
|
||||||
**Class Props:**
|
|
||||||
```php
|
|
||||||
/**
|
|
||||||
* The name of the field being resolved
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $fieldName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AST of all nodes referencing this field in the query.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var FieldNode[]
|
|
||||||
*/
|
|
||||||
public $fieldNodes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expected return type of the field being resolved
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var ScalarType|ObjectType|InterfaceType|UnionType|EnumType|ListOfType|NonNull
|
|
||||||
*/
|
|
||||||
public $returnType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parent type of the field being resolved
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var ObjectType
|
|
||||||
*/
|
|
||||||
public $parentType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path to this field from the very root value
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of a schema used for execution
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var Schema
|
|
||||||
*/
|
|
||||||
public $schema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AST of all fragments defined in query
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var FragmentDefinitionNode[]
|
|
||||||
*/
|
|
||||||
public $fragments;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Root value passed to query execution
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
public $rootValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AST of operation definition node (query, mutation)
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var OperationDefinitionNode
|
|
||||||
*/
|
|
||||||
public $operation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of variables passed to query execution
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $variableValues;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Class Methods:**
|
|
||||||
```php
|
|
||||||
/**
|
|
||||||
* Helper method that returns names of all fields selected in query for
|
|
||||||
* $this->fieldName up to $depth levels
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* query MyQuery{
|
|
||||||
* {
|
|
||||||
* root {
|
|
||||||
* id,
|
|
||||||
* nested {
|
|
||||||
* nested1
|
|
||||||
* nested2 {
|
|
||||||
* nested3
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* Given this ResolveInfo instance is a part of "root" field resolution, and $depth === 1,
|
|
||||||
* method will return:
|
|
||||||
* [
|
|
||||||
* 'id' => true,
|
|
||||||
* 'nested' => [
|
|
||||||
* nested1 => true,
|
|
||||||
* nested2 => true
|
|
||||||
* ]
|
|
||||||
* ]
|
|
||||||
*
|
|
||||||
* Warning: this method it is a naive implementation which does not take into account
|
|
||||||
* conditional typed fragments. So use it with care for fields of interface and union types.
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
* @param int $depth How many levels to include in output
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
function getFieldSelection($depth = 0)
|
|
||||||
```
|
|
||||||
# GraphQL\Validator\DocumentValidator
|
# GraphQL\Validator\DocumentValidator
|
||||||
Implements the "Validation" section of the spec.
|
Implements the "Validation" section of the spec.
|
||||||
|
|
||||||
@ -1888,3 +1911,186 @@ function getOriginalInput($key)
|
|||||||
*/
|
*/
|
||||||
function isReadOnly()
|
function isReadOnly()
|
||||||
```
|
```
|
||||||
|
# GraphQL\Utils\BuildSchema
|
||||||
|
Build instance of `GraphQL\Type\Schema` out of type language definition (string or parsed AST)
|
||||||
|
See [section in docs](type-system/type-language.md) for details.
|
||||||
|
|
||||||
|
**Class Methods:**
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* This takes the ast of a schema document produced by the parse function in
|
||||||
|
* GraphQL\Language\Parser.
|
||||||
|
*
|
||||||
|
* If no schema definition is provided, then it will look for types named Query
|
||||||
|
* and Mutation.
|
||||||
|
*
|
||||||
|
* Given that AST it constructs a GraphQL\Type\Schema. The resulting schema
|
||||||
|
* has no resolve methods, so execution will use default resolvers.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param DocumentNode $ast
|
||||||
|
* @param callable $typeConfigDecorator
|
||||||
|
* @return Schema
|
||||||
|
* @throws Error
|
||||||
|
*/
|
||||||
|
static function buildAST(GraphQL\Language\AST\DocumentNode $ast, callable $typeConfigDecorator = null)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* A helper function to build a GraphQLSchema directly from a source
|
||||||
|
* document.
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param DocumentNode|Source|string $source
|
||||||
|
* @param callable $typeConfigDecorator
|
||||||
|
* @return Schema
|
||||||
|
*/
|
||||||
|
static function build($source, callable $typeConfigDecorator = null)
|
||||||
|
```
|
||||||
|
# GraphQL\Utils\AST
|
||||||
|
Various utilities dealing with AST
|
||||||
|
|
||||||
|
**Class Methods:**
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Convert representation of AST as an associative array to instance of GraphQL\Language\AST\Node.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* ```php
|
||||||
|
* Node::fromArray([
|
||||||
|
* 'kind' => 'ListValue',
|
||||||
|
* 'values' => [
|
||||||
|
* ['kind' => 'StringValue', 'value' => 'my str'],
|
||||||
|
* ['kind' => 'StringValue', 'value' => 'my other str']
|
||||||
|
* ],
|
||||||
|
* 'loc' => ['start' => 21, 'end' => 25]
|
||||||
|
* ]);
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Will produce instance of `ListValueNode` where `values` prop is a lazily-evaluated `NodeList`
|
||||||
|
* returning instances of `StringValueNode` on access.
|
||||||
|
*
|
||||||
|
* This is a reverse operation for AST::toArray($node)
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param array $node
|
||||||
|
* @return Node
|
||||||
|
*/
|
||||||
|
static function fromArray(array $node)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Convert AST node to serializable array
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param Node $node
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
static function toArray(GraphQL\Language\AST\Node $node)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Produces a GraphQL Value AST given a PHP value.
|
||||||
|
*
|
||||||
|
* Optionally, a GraphQL type may be provided, which will be used to
|
||||||
|
* disambiguate between value primitives.
|
||||||
|
*
|
||||||
|
* | PHP Value | GraphQL Value |
|
||||||
|
* | ------------- | -------------------- |
|
||||||
|
* | Object | Input Object |
|
||||||
|
* | Assoc Array | Input Object |
|
||||||
|
* | Array | List |
|
||||||
|
* | Boolean | Boolean |
|
||||||
|
* | String | String / Enum Value |
|
||||||
|
* | Int | Int |
|
||||||
|
* | Float | Int / Float |
|
||||||
|
* | Mixed | Enum Value |
|
||||||
|
* | null | NullValue |
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param $value
|
||||||
|
* @param InputType $type
|
||||||
|
* @return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode
|
||||||
|
*/
|
||||||
|
static function astFromValue($value, GraphQL\Type\Definition\InputType $type)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Produces a PHP value given a GraphQL Value AST.
|
||||||
|
*
|
||||||
|
* A GraphQL type must be provided, which will be used to interpret different
|
||||||
|
* GraphQL Value literals.
|
||||||
|
*
|
||||||
|
* Returns `null` when the value could not be validly coerced according to
|
||||||
|
* the provided type.
|
||||||
|
*
|
||||||
|
* | GraphQL Value | PHP Value |
|
||||||
|
* | -------------------- | ------------- |
|
||||||
|
* | Input Object | Assoc Array |
|
||||||
|
* | List | Array |
|
||||||
|
* | Boolean | Boolean |
|
||||||
|
* | String | String |
|
||||||
|
* | Int / Float | Int / Float |
|
||||||
|
* | Enum Value | Mixed |
|
||||||
|
* | Null Value | null |
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param $valueNode
|
||||||
|
* @param InputType $type
|
||||||
|
* @param null $variables
|
||||||
|
* @return array|null|\stdClass
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
static function valueFromAST($valueNode, GraphQL\Type\Definition\InputType $type, $variables = null)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Returns type definition for given AST Type node
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param Schema $schema
|
||||||
|
* @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode
|
||||||
|
* @return Type
|
||||||
|
* @throws InvariantViolation
|
||||||
|
*/
|
||||||
|
static function typeFromAST(GraphQL\Type\Schema $schema, $inputTypeNode)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* Returns operation type ("query", "mutation" or "subscription") given a document and operation name
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
* @param DocumentNode $document
|
||||||
|
* @param string $operationName
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
static function getOperation(GraphQL\Language\AST\DocumentNode $document, $operationName = null)
|
||||||
|
```
|
||||||
|
# GraphQL\Utils\SchemaPrinter
|
||||||
|
Given an instance of Schema, prints it in GraphQL type language.
|
||||||
|
|
||||||
|
**Class Methods:**
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @param Schema $schema
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function doPrint(GraphQL\Type\Schema $schema)
|
||||||
|
```
|
||||||
|
|
||||||
|
```php
|
||||||
|
/**
|
||||||
|
* @api
|
||||||
|
* @param Schema $schema
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
static function printIntrosepctionSchema(GraphQL\Type\Schema $schema)
|
||||||
|
```
|
||||||
|
@ -21,7 +21,7 @@ DocumentValidator::addRule($rule);
|
|||||||
|
|
||||||
GraphQL::executeQuery(/*...*/);
|
GraphQL::executeQuery(/*...*/);
|
||||||
```
|
```
|
||||||
This will set the rule globally. Alternatively you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
This will set the rule globally. Alternatively, you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
||||||
|
|
||||||
To customize field score add **complexity** function to field definition:
|
To customize field score add **complexity** function to field definition:
|
||||||
```php
|
```php
|
||||||
@ -51,7 +51,7 @@ $type = new ObjectType([
|
|||||||
# Limiting Query Depth
|
# Limiting Query Depth
|
||||||
|
|
||||||
This is a PHP port of [Limiting Query Depth](http://sangria-graphql.org/learn/#limiting-query-depth) in Sangria implementation.
|
This is a PHP port of [Limiting Query Depth](http://sangria-graphql.org/learn/#limiting-query-depth) in Sangria implementation.
|
||||||
For example max depth of the introspection query is **7**.
|
For example, max depth of the introspection query is **7**.
|
||||||
|
|
||||||
It is disabled by default. To enable it, add following validation rule:
|
It is disabled by default. To enable it, add following validation rule:
|
||||||
|
|
||||||
@ -67,16 +67,16 @@ DocumentValidator::addRule($rule);
|
|||||||
GraphQL::executeQuery(/*...*/);
|
GraphQL::executeQuery(/*...*/);
|
||||||
```
|
```
|
||||||
|
|
||||||
This will set the rule globally. Alternatively you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
This will set the rule globally. Alternatively, you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
||||||
|
|
||||||
# Disabling Introspection
|
# Disabling Introspection
|
||||||
[Introspection](http://graphql.org/learn/introspection/) is a mechanism for fetching schema structure.
|
[Introspection](http://graphql.org/learn/introspection/) is a mechanism for fetching schema structure.
|
||||||
It is used by tools like GraphiQL for autocompletion, query validation, etc.
|
It is used by tools like GraphiQL for auto-completion, query validation, etc.
|
||||||
|
|
||||||
Introspection is enabled by default. It means that anybody can get full description of your schema by
|
Introspection is enabled by default. It means that anybody can get a full description of your schema by
|
||||||
sending special query containing meta fields **__type** and **__schema** .
|
sending a special query containing meta fields **__type** and **__schema** .
|
||||||
|
|
||||||
If you are not planning to expose your API to general public, it makes sense to disable this feature.
|
If you are not planning to expose your API to the general public, it makes sense to disable this feature.
|
||||||
|
|
||||||
GraphQL PHP provides you separate validation rule which prohibits queries that contain
|
GraphQL PHP provides you separate validation rule which prohibits queries that contain
|
||||||
**__type** or **__schema** fields. To disable introspection, add following rule:
|
**__type** or **__schema** fields. To disable introspection, add following rule:
|
||||||
@ -91,4 +91,4 @@ DocumentValidator::addRule(new DisableIntrospection());
|
|||||||
|
|
||||||
GraphQL::executeQuery(/*...*/);
|
GraphQL::executeQuery(/*...*/);
|
||||||
```
|
```
|
||||||
This will set the rule globally. Alternatively you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
This will set the rule globally. Alternatively, you can provide validation rules [per execution](executing-queries.md#custom-validation-rules).
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
# Built-in directives
|
# Built-in directives
|
||||||
Directive is a way for client to give GraphQL server additional context and hints on how to execute
|
The directive is a way for a client to give GraphQL server additional context and hints on how to execute
|
||||||
the query. Directive can be attached to a field or fragment inclusion, and can affect execution of the
|
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.
|
query in any way the server desires.
|
||||||
|
|
||||||
GraphQL specification includes two built-in directives:
|
GraphQL specification includes two built-in directives:
|
||||||
|
|
||||||
* `@include(if: Boolean)` Only include this field or fragment in the result if the argument is `true`
|
* **@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`
|
* **@skip(if: Boolean)** Skip this field or fragment if the argument is **true**
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```graphql
|
```graphql
|
||||||
@ -19,47 +19,43 @@ query Hero($episode: Episode, $withFriends: Boolean!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Here if `$withFriends` variable is set to `false` - friends section will be ignored and excluded
|
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
|
from the response. Important implementation detail: those fields will never be executed
|
||||||
(not just removed from response after execution).
|
(not just removed from response after execution).
|
||||||
|
|
||||||
# Custom directives
|
# Custom directives
|
||||||
**graphql-php** supports custom directives even though their presence does not affect execution of fields.
|
**graphql-php** supports custom directives even though their presence does not affect the execution of fields.
|
||||||
But you can use `GraphQL\Type\Definition\ResolveInfo` in field resolvers to modify the output depending
|
But you can use [`GraphQL\Type\Definition\ResolveInfo`](../reference.md#graphqltypedefinitionresolveinfo)
|
||||||
on those directives or perform statistics collection.
|
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.
|
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`
|
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:
|
(or one of its subclasses) which accepts an array of following options:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
|
use GraphQL\Type\Definition\DirectiveLocation;
|
||||||
use GraphQL\Type\Definition\FieldArgument;
|
use GraphQL\Type\Definition\FieldArgument;
|
||||||
|
|
||||||
$trackDirective = new Directive([
|
$trackDirective = new Directive([
|
||||||
'name' => 'track',
|
'name' => 'track',
|
||||||
'description' => 'Instruction to record usage of the field by client'
|
'description' => 'Instruction to record usage of the field by client',
|
||||||
'locations' => [
|
'locations' => [
|
||||||
Directive::LOCATION_FIELD,
|
DirectiveLocation::FIELD,
|
||||||
],
|
],
|
||||||
'args' => [
|
'args' => [
|
||||||
new FieldArgument([
|
new FieldArgument([
|
||||||
'name' => 'details',
|
'name' => 'details',
|
||||||
'type' => Type::string(),
|
'type' => Type::string(),
|
||||||
'description' => 'String with additional details of field usage scenario'
|
'description' => 'String with additional details of field usage scenario',
|
||||||
'defaultValue' => ''
|
'defaultValue' => ''
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Directive location can be one of the following values:
|
See possible directive locations in
|
||||||
|
[`GraphQL\Type\Definition\DirectiveLocation`](../reference.md#graphqltypedefinitiondirectivelocation).
|
||||||
* `Directive::LOCATION_QUERY`
|
|
||||||
* `Directive::LOCATION_MUTATION`
|
|
||||||
* `Directive::LOCATION_SUBSCRIPTION`
|
|
||||||
* `Directive::LOCATION_FIELD`
|
|
||||||
* `Directive::LOCATION_FRAGMENT_DEFINITION`
|
|
||||||
* `Directive::LOCATION_FRAGMENT_SPREAD`
|
|
||||||
* `Directive::LOCATION_INLINE_FRAGMENT`
|
|
||||||
|
@ -6,6 +6,7 @@ In **graphql-php** enum type is an instance of `GraphQL\Type\Definition\EnumType
|
|||||||
which accepts configuration array in constructor:
|
which accepts configuration array in constructor:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
|
||||||
$episodeEnum = new EnumType([
|
$episodeEnum = new EnumType([
|
||||||
@ -28,11 +29,11 @@ $episodeEnum = new EnumType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
This example uses **inline** style for Enum Type definition, but you can also use
|
This example uses an **inline** style for Enum Type definition, but you can also use
|
||||||
[inheritance or type language](index.md#type-definition-styles).
|
[inheritance or type language](index.md#type-definition-styles).
|
||||||
|
|
||||||
# Configuration options
|
# Configuration options
|
||||||
Enum Type constructor accepts array with following options:
|
Enum Type constructor accepts an array with following options:
|
||||||
|
|
||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
@ -55,6 +56,9 @@ If internal representation of enumerated item is the same as item name, then you
|
|||||||
following shorthand for definition:
|
following shorthand for definition:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
|
||||||
$episodeEnum = new EnumType([
|
$episodeEnum = new EnumType([
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'description' => 'One of the films in the Star Wars Trilogy',
|
'description' => 'One of the films in the Star Wars Trilogy',
|
||||||
@ -64,6 +68,9 @@ $episodeEnum = new EnumType([
|
|||||||
|
|
||||||
which is equivalent of:
|
which is equivalent of:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
|
||||||
$episodeEnum = new EnumType([
|
$episodeEnum = new EnumType([
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'description' => 'One of the films in the Star Wars Trilogy',
|
'description' => 'One of the films in the Star Wars Trilogy',
|
||||||
@ -75,9 +82,12 @@ $episodeEnum = new EnumType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
which is in turn equivalent of full form:
|
which is in turn equivalent of the full form:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
|
||||||
$episodeEnum = new EnumType([
|
$episodeEnum = new EnumType([
|
||||||
'name' => 'Episode',
|
'name' => 'Episode',
|
||||||
'description' => 'One of the films in the Star Wars Trilogy',
|
'description' => 'One of the films in the Star Wars Trilogy',
|
||||||
@ -90,11 +100,12 @@ $episodeEnum = new EnumType([
|
|||||||
```
|
```
|
||||||
|
|
||||||
# Field Resolution
|
# Field Resolution
|
||||||
When object field is of Enum Type, field resolver is expected to return internal
|
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
|
representation of corresponding Enum item (**value** in config). **graphql-php** will
|
||||||
then serialize this **value** to **name** to include in response:
|
then serialize this **value** to **name** to include in response:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
@ -127,14 +138,18 @@ $heroType = new ObjectType([
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
])
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Reverse is true when enum is used as input type (e.g. as field argument).
|
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.
|
GraphQL will treat enum input as **name** and convert it into **value** before passing to your app.
|
||||||
|
|
||||||
For example, given object type definition:
|
For example, given object type definition:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$heroType = new ObjectType([
|
$heroType = new ObjectType([
|
||||||
'name' => 'Hero',
|
'name' => 'Hero',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -142,17 +157,17 @@ $heroType = new ObjectType([
|
|||||||
'type' => Type::boolean(),
|
'type' => Type::boolean(),
|
||||||
'args' => [
|
'args' => [
|
||||||
'episode' => Type::nonNull($enumType)
|
'episode' => Type::nonNull($enumType)
|
||||||
]
|
],
|
||||||
'resolve' => function($_value, $args) {
|
'resolve' => function($_value, $args) {
|
||||||
return $args['episode'] === 5 ? true : false;
|
return $args['episode'] === 5 ? true : false;
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
])
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Then following query:
|
Then following query:
|
||||||
```
|
```graphql
|
||||||
fragment on Hero {
|
fragment on Hero {
|
||||||
appearsInNewHope: appearsIn(NEWHOPE)
|
appearsInNewHope: appearsIn(NEWHOPE)
|
||||||
appearsInEmpire: appearsIn(EMPIRE)
|
appearsInEmpire: appearsIn(EMPIRE)
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
# Type System
|
# Type System
|
||||||
To start using GraphQL you are expected to implement a type hierarchy and expose it as [Schema](schema.md).
|
To start using GraphQL you are expected to implement a type hierarchy and expose it as [Schema](schema.md).
|
||||||
|
|
||||||
In **graphql-php** `type` is an instance of internal class from
|
In graphql-php **type** is an instance of internal class from
|
||||||
`GraphQL\Type\Definition` namespace: `ScalarType`, `ObjectType`, `InterfaceType`,
|
`GraphQL\Type\Definition` namespace: [`ObjectType`](object-types.md),
|
||||||
`UnionType`, `InputObjectType` (or one of it's subclasses).
|
[`InterfaceType`](interfaces.md), [`UnionType`](unions.md), [`InputObjectType`](input-types.md),
|
||||||
|
[`ScalarType`](scalar-types.md), [`EnumType`](enum-types.md) (or one of subclasses).
|
||||||
|
|
||||||
But most of the types in your schema will be [object types](object-types.md).
|
But most of the types in your schema will be [object types](object-types.md).
|
||||||
|
|
||||||
@ -68,16 +69,16 @@ input HelloInput {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[Read more](type-language.md) about it in a dedicated docs section.
|
Read more about type language definitions in a [dedicated docs section](type-language.md).
|
||||||
|
|
||||||
# Type Registry
|
# Type Registry
|
||||||
Every type must be presented in Schema by single instance (**graphql-php**
|
Every type must be presented in Schema by a single instance (**graphql-php**
|
||||||
throws when it discovers several instances with the same `name` in schema).
|
throws when it discovers several instances with the same **name** in the schema).
|
||||||
|
|
||||||
Therefore if you define your type as separate PHP class you must ensure that only one
|
Therefore if you define your type as separate PHP class you must ensure that only one
|
||||||
instance of that class is added to schema.
|
instance of that class is added to the schema.
|
||||||
|
|
||||||
Typical way to do this is to create registry of your types:
|
The typical way to do this is to create a registry of your types:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
@ -118,8 +119,9 @@ class MyAType extends ObjectType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Obviously you can automate this registry as you wish to reduce boilerplate or even
|
Obviously, you can automate this registry as you wish to reduce boilerplate or even
|
||||||
introduce Dependency Injection Container if your types have other dependencies.
|
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 the registry could be static - 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.
|
||||||
|
@ -1,33 +1,82 @@
|
|||||||
|
# Mutations
|
||||||
|
Mutation is just a field of a regular [Object Type](object-types.md) with arguments.
|
||||||
|
For GraphQL PHP runtime there is no difference between query fields with arguments and mutations.
|
||||||
|
They are executed [almost](http://facebook.github.io/graphql/#sec-Mutation) identically.
|
||||||
|
To some extent, Mutation is just a convention described in the GraphQL spec.
|
||||||
|
|
||||||
|
Here is an example of a mutation operation:
|
||||||
|
```graphql
|
||||||
|
mutation CreateReviewForEpisode($ep: EpisodeInput!, $review: ReviewInput!) {
|
||||||
|
createReview(episode: $ep, review: $review) {
|
||||||
|
stars
|
||||||
|
commentary
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To execute such a mutation, you need **Mutation** type [at the root of your schema](schema.md):
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
|
$myMutationType = new ObjectType([
|
||||||
|
'name' => 'Mutation',
|
||||||
|
'fields' => [
|
||||||
|
// List of mutations:
|
||||||
|
'createReview' => [
|
||||||
|
'args' => [
|
||||||
|
'episode' => Type::nonNull($episodeInputType),
|
||||||
|
'review' => Type::nonNull($reviewInputType)
|
||||||
|
],
|
||||||
|
'type' => new ObjectType([
|
||||||
|
'name' => 'CreateReviewOutput',
|
||||||
|
'fields' => [
|
||||||
|
'stars' => ['type' => Type::int()],
|
||||||
|
'commentary' => ['type' => Type::string()]
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
// ... other mutations
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
As you can see, the only difference from regular object type is the semantics of field names
|
||||||
|
(verbs vs nouns).
|
||||||
|
|
||||||
|
Also as we see arguments can be of complex types. To leverage the full power of mutations
|
||||||
|
(and field arguments in general) you must learn how to create complex input types.
|
||||||
|
|
||||||
|
|
||||||
# About Input and Output Types
|
# About Input and Output Types
|
||||||
GraphQL receives data from clients via [Field Arguments](object-types.md#field-arguments).
|
All types in GraphQL are of two categories: **input** and **output**.
|
||||||
|
|
||||||
Both - fields and arguments require **type** option in definition. But expected value of this option
|
|
||||||
is different for fields and arguments, as in GraphQL argument is conceptually input while field is conceptually
|
|
||||||
output.
|
|
||||||
|
|
||||||
Consequentially all types in GraphQL are of two categories: **input** and **output**.
|
|
||||||
|
|
||||||
* **Output** types (or field types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), [Object](object-types.md),
|
* **Output** types (or field types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), [Object](object-types.md),
|
||||||
[Interface](interfaces.md), [Union](unions.md)
|
[Interface](interfaces.md), [Union](unions.md)
|
||||||
|
|
||||||
* **Input** types (or argument types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), InputObject
|
* **Input** types (or argument types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), InputObject
|
||||||
|
|
||||||
Obviously [NonNull and List](lists-and-nonnulls.md) types belong to both categories depending on their
|
Obviously, [NonNull and List](lists-and-nonnulls.md) types belong to both categories depending on their
|
||||||
inner type.
|
inner type.
|
||||||
|
|
||||||
Until now all examples of field **arguments** in this documentation were of [Scalar](scalar-types.md) or
|
Until now all examples of field **arguments** in this documentation were of [Scalar](scalar-types.md) or
|
||||||
[Enum](enum-types.md) types. But you can also easily pass complex objects.
|
[Enum](enum-types.md) types. But you can also pass complex objects.
|
||||||
|
|
||||||
This is particularly valuable in the case of mutations, where input data might be rather complex.
|
This is particularly valuable in case of mutations, where input data might be rather complex.
|
||||||
|
|
||||||
# Input Object Type
|
# Input Object Type
|
||||||
GraphQL specification defines Input Object Type for complex inputs. It is similar to ObjectType
|
GraphQL specification defines Input Object Type for complex inputs. It is similar to ObjectType
|
||||||
except that it's fields have no **args** or **resolve** options and their **type** must be input type.
|
except that it's fields have no **args** or **resolve** options and their **type** must be input type.
|
||||||
|
|
||||||
In **graphql-php** Input Object Type is an instance of `GraphQL\Type\Definition\InputObjectType`
|
In graphql-php **Input Object Type** is an instance of `GraphQL\Type\Definition\InputObjectType`
|
||||||
(or one of it subclasses) which accepts configuration array in constructor:
|
(or one of it subclasses) which accepts configuration array in constructor:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
|
|
||||||
$filters = new InputObjectType([
|
$filters = new InputObjectType([
|
||||||
'name' => 'StoryFiltersInput',
|
'name' => 'StoryFiltersInput',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -50,12 +99,12 @@ $filters = new InputObjectType([
|
|||||||
Every field may be of other InputObjectType (thus complex hierarchies of inputs are possible)
|
Every field may be of other InputObjectType (thus complex hierarchies of inputs are possible)
|
||||||
|
|
||||||
# Configuration options
|
# Configuration options
|
||||||
Constructor of InputObjectType accepts array with only 3 options:
|
The constructor of InputObjectType accepts array with only 3 options:
|
||||||
|
|
||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------------ | -------- | -----
|
------------ | -------- | -----
|
||||||
name | `string` | **Required.** Unique name of this object type within Schema
|
name | `string` | **Required.** Unique name of this object type within Schema
|
||||||
fields | `array` or `callback` returning `array` | **Required**. Array describing object fields (see below).
|
fields | `array` or `callable` | **Required**. An array describing object fields or callable returning such an array (see below).
|
||||||
description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
|
|
||||||
Every field is an array with following entries:
|
Every field is an array with following entries:
|
||||||
@ -63,7 +112,7 @@ Every field is an array with following entries:
|
|||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
name | `string` | **Required.** Name of the input field. When not set - inferred from **fields** array key
|
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](input-types.md) (`Scalar`, `Enum`, `InputObjectType` + any combination of those with `NonNull` and `List` modifiers)
|
type | `Type` | **Required.** Instance of one of [Input Types](input-types.md) (**Scalar**, **Enum**, **InputObjectType** + any combination of those with **nonNull** and **listOf** modifiers)
|
||||||
description | `string` | Plain-text description of this input field for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
description | `string` | Plain-text description of this input field for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
defaultValue | `scalar` | Default value of this input field
|
defaultValue | `scalar` | Default value of this input field
|
||||||
|
|
||||||
@ -71,6 +120,10 @@ defaultValue | `scalar` | Default value of this input field
|
|||||||
In the example above we defined our InputObjectType. Now let's use it in one of field arguments:
|
In the example above we defined our InputObjectType. Now let's use it in one of field arguments:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
$queryType = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
|
@ -3,9 +3,10 @@ An Interface is an abstract type that includes a certain set of fields that a
|
|||||||
type must include to implement the interface.
|
type must include to implement the interface.
|
||||||
|
|
||||||
In **graphql-php** interface type is an instance of `GraphQL\Type\Definition\InterfaceType`
|
In **graphql-php** interface type is an instance of `GraphQL\Type\Definition\InterfaceType`
|
||||||
(or one of it subclasses) which accepts configuration array in constructor:
|
(or one of its subclasses) which accepts configuration array in a constructor:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
|
||||||
@ -32,21 +33,25 @@ $character = new InterfaceType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
This example uses **inline** style for Interface definition, but you can also use
|
This example uses **inline** style for Interface definition, but you can also use
|
||||||
[inheritance](index.md#type-definition-styles).
|
[inheritance or type language](index.md#type-definition-styles).
|
||||||
|
|
||||||
# Configuration options
|
# Configuration options
|
||||||
Constructor of InterfaceType accepts an array. Below is a full list of allowed options:
|
The constructor of InterfaceType accepts an array. Below is a full list of allowed options:
|
||||||
|
|
||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
name | `string` | **Required.** Unique name of this interface type within Schema
|
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](object-types.md#field-configuration-options)
|
fields | `array` | **Required.** List of fields required to be defined by interface implementors. Same as [Fields for Object Type](object-types.md#field-configuration-options)
|
||||||
description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
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`.
|
resolveType | `callback` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**<br> Receives **$value** from resolver of the parent field and returns concrete interface implementor for this **$value**.
|
||||||
|
|
||||||
# Implementing interface
|
# Implementing interface
|
||||||
To implement the Interface simply add it to **interfaces** array of Object Type definition:
|
To implement the Interface simply add it to **interfaces** array of Object Type definition:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$humanType = new ObjectType([
|
$humanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
@ -71,7 +76,7 @@ The only exception is when object's field type is more specific than the type of
|
|||||||
(see [Covariant return types for interface fields](#covariant-return-types-for-interface-fields) below)
|
(see [Covariant return types for interface fields](#covariant-return-types-for-interface-fields) below)
|
||||||
|
|
||||||
# Covariant return types for interface fields
|
# Covariant return types for interface fields
|
||||||
Object types implementing interface may change field type to more specific.
|
Object types implementing interface may change the field type to more specific.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -86,9 +91,13 @@ type B implements A {
|
|||||||
|
|
||||||
# Sharing Interface fields
|
# Sharing Interface fields
|
||||||
Since every Object Type implementing an Interface must have the same set of fields - it often makes
|
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:
|
sense to reuse field definitions of Interface in Object Types:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$humanType = new ObjectType([
|
$humanType = new ObjectType([
|
||||||
'name' => 'Human',
|
'name' => 'Human',
|
||||||
'interfaces' => [
|
'interfaces' => [
|
||||||
@ -102,26 +111,26 @@ $humanType = new ObjectType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
In this case field definitions are created only once (as a part of Interface Type) and then
|
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 kilobytes + ensures that
|
reused by all interface implementors. It can save several microseconds and kilobytes + ensures that
|
||||||
field definitions of Interface and implementors are always in sync.
|
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
|
Yet it creates a problem with the resolution of such fields. There are two ways how shared fields could
|
||||||
be resolved:
|
be resolved:
|
||||||
|
|
||||||
1. If field resolution algorithm is the same for all Interface implementors - you can simply add
|
1. If field resolution algorithm is the same for all Interface implementors - you can simply add
|
||||||
**resolve** option to field definition in Interface itself.
|
**resolve** option to field definition in Interface itself.
|
||||||
|
|
||||||
2. If field resolution varies from implementor to implementor - you can specify **resolveField**
|
2. If field resolution varies for different implementations - you can specify **resolveField**
|
||||||
option in [Object Type config](object-types.md#configuration-options) and handle field
|
option in [Object Type config](object-types.md#configuration-options) and handle field
|
||||||
resolutions there
|
resolutions there
|
||||||
(Note: **resolve** option in field definition has precedence over **resolveField** option in object type definition)
|
(Note: **resolve** option in field definition has precedence over **resolveField** option in object type definition)
|
||||||
|
|
||||||
# Interface role in data fetching
|
# Interface role in data fetching
|
||||||
The only responsibility of interface in Data Fetching process is to return concrete Object Type
|
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
|
for given **$value** in **resolveType**. Then resolution of fields is delegated to resolvers of this
|
||||||
concrete Object Type.
|
concrete Object Type.
|
||||||
|
|
||||||
If **resolveType** option is omitted, **graphql-php** will loop through all interface implementors and
|
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
|
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.
|
than single **resolveType** call. So it is recommended to define **resolveType** whenever possible.
|
||||||
|
@ -21,17 +21,18 @@ $userType = new ObjectType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Resolvers for such fields are expected to return `array` or instance of PHP internal `Traversable`
|
Resolvers for such fields are expected to return **array** or instance of PHP's built-in **Traversable**
|
||||||
interface (`null` is allowed by default too).
|
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
|
If returned value is not of one of these types - **graphql-php** will add an error to result
|
||||||
and set field value to `null` (only if field is nullable, see below for non-null fields).
|
and set the field value to **null** (only if the field is nullable, see below for non-null fields).
|
||||||
|
|
||||||
# Non-Null fields
|
# Non-Null fields
|
||||||
By default in GraphQL every field can have `null` value. To indicate that some field always
|
By default in GraphQL, every field can have a **null** value. To indicate that some field always
|
||||||
returns `non-null` value - use `GraphQL\Type\Definition\Type::nonNull()` modifier:
|
returns **non-null** value - use `GraphQL\Type\Definition\Type::nonNull()` modifier:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
@ -54,8 +55,8 @@ $humanType = new ObjectType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
If resolver of non-null field returns `null`, **graphql-php** will add an error to
|
If resolver of non-null field returns **null**, graphql-php will add an error to
|
||||||
result and exclude whole object from output (error will bubble to first nullable parent
|
result and exclude the whole object from the output (an error will bubble to first
|
||||||
field which will be set to `null`).
|
nullable parent field which will be set to **null**).
|
||||||
|
|
||||||
Read section on [Data Fetching](../data-fetching.md) for details.
|
Read the section on [Data Fetching](../data-fetching.md) for details.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# Object Type Definition
|
# Object Type Definition
|
||||||
Object Type is the most frequently used primitive in typical GraphQL application.
|
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
|
Conceptually Object Type is a collection of Fields. Each field, in turn,
|
||||||
has it's own type which allows to build complex hierarchies.
|
has its own type which allows building complex hierarchies.
|
||||||
|
|
||||||
In **graphql-php** object type is an instance of `GraphQL\Type\Definition\ObjectType`
|
In **graphql-php** object type is an instance of `GraphQL\Type\Definition\ObjectType`
|
||||||
(or one of it subclasses) which accepts configuration array in constructor:
|
(or one of it subclasses) which accepts configuration array in constructor:
|
||||||
@ -66,11 +66,11 @@ Object type constructor expects configuration array. Below is a full list of ava
|
|||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------------ | -------- | -----
|
------------ | -------- | -----
|
||||||
name | `string` | **Required.** Unique name of this object type within Schema
|
name | `string` | **Required.** Unique name of this object type within Schema
|
||||||
fields | `array` or `callable` returning `array` | **Required**. Array describing object fields. See [Fields](#field-definitions) section below for expected structure of each array entry. See also section on [Circular types](#recurring-and-circular-types) for explanation of when to use callable for this option.
|
fields | `array` or `callable` | **Required**. An array describing object fields or callable returning such an array. See [Fields](#field-definitions) section below for expected structure of each array entry. See also the section on [Circular types](#recurring-and-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](https://github.com/graphql/graphiql) for auto-generated documentation)
|
description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
interfaces | `array` or `callable` returning `array` | List of interfaces implemented by this type. See [Interface Types](interfaces.md) for details. See also section on [Circular types](#recurring-and-circular-types) for explanation of when to use callable for this option.
|
interfaces | `array` or `callable` | List of interfaces implemented by this type or callable returning such a list. See [Interface Types](interfaces.md) for details. See also the section on [Circular types](#recurring-and-circular-types) for an explanation of when to use callable for this option.
|
||||||
isTypeOf | `callable` returning `boolean` | **function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)** Expected to return `true` if `$value` qualifies for this type (see section about [Abstract Type Resolution](interfaces.md#interface-role-in-data-fetching) for explanation).
|
isTypeOf | `callable` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**<br> Expected to return **true** if **$value** qualifies for this type (see section about [Abstract Type Resolution](interfaces.md#interface-role-in-data-fetching) for explanation).
|
||||||
resolveField | `callable` returning `mixed` | **function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)** Given the `$value` of this type it is expected to return value for field defined in `$info->fieldName`. Good place to define type-specific strategy for field resolution. See section on [Data Fetching](../data-fetching.md) for details.
|
resolveField | `callable` | **function($value, $args, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**<br> 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 section on [Data Fetching](../data-fetching.md) for details.
|
||||||
|
|
||||||
# Field configuration options
|
# Field configuration options
|
||||||
Below is a full list of available field configuration options:
|
Below is a full list of available field configuration options:
|
||||||
@ -78,10 +78,10 @@ Below is a full list of available field configuration options:
|
|||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
name | `string` | **Required.** Name of the field. When not set - inferred from **fields** array key (read about [shorthand field definition](#shorthand-field-definitions) below)
|
name | `string` | **Required.** Name of the field. When not set - inferred from **fields** array key (read about [shorthand field definition](#shorthand-field-definitions) below)
|
||||||
type | `Type` | **Required.** Instance of internal or custom type. Note: type must be represented by single instance within schema (see also [Type Registry](index.md#type-registry))
|
type | `Type` | **Required.** An instance of internal or custom type. Note: type must be represented by a single instance within one schema (see also [Type Registry](index.md#type-registry))
|
||||||
args | `array` | Array of possible type arguments. Each entry is expected to be an array with keys: **name**, **type**, **description**, **defaultValue**. See [Field Arguments](#field-arguments) section below.
|
args | `array` | An array of possible type arguments. Each entry is expected to be an array with keys: **name**, **type**, **description**, **defaultValue**. See [Field Arguments](#field-arguments) section below.
|
||||||
resolve | `callable` | **function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)** Given the `$value` of this type it is expected to return value for current field. See section on [Data Fetching](../data-fetching.md) for details
|
resolve | `callable` | **function($value, $args, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**<br> Given the **$value** of this type, it is expected to return actual value of the current field. See section on [Data Fetching](../data-fetching.md) for details
|
||||||
complexity | `callable` | **function($childrenComplexity, $args)** Used to restrict query complexity. Feature is disabled by default, read section about [Security](../security.md#query-complexity-analysis) to use it.
|
complexity | `callable` | **function($childrenComplexity, $args)**<br> Used to restrict query complexity. The feature is disabled by default, read about [Security](../security.md#query-complexity-analysis) to use it.
|
||||||
description | `string` | Plain-text description of this field for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
description | `string` | Plain-text description of this field for clients (e.g. used by [GraphiQL](https://github.com/graphql/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)
|
deprecationReason | `string` | Text describing why this field is deprecated. When not empty - field will not be returned by introspection queries (unless forced)
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ Each argument is an array with following options:
|
|||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
name | `string` | **Required.** Name of the argument. When not set - inferred from **args** array key
|
name | `string` | **Required.** Name of the argument. When not set - inferred from **args** array key
|
||||||
type | `Type` | **Required.** Instance of one of [Input Types](input-types.md) (`scalar`, `enum`, `InputObjectType` + any combination of those with `nonNull` and `listOf` modifiers)
|
type | `Type` | **Required.** Instance of one of [Input Types](input-types.md) (**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](https://github.com/graphql/graphiql) for auto-generated documentation)
|
description | `string` | Plain-text description of this argument for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation)
|
||||||
defaultValue | `scalar` | Default value for this argument
|
defaultValue | `scalar` | Default value for this argument
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ which is equivalent of:
|
|||||||
'fieldName' => ['type' => $fieldName]
|
'fieldName' => ['type' => $fieldName]
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
which is in turn equivalent of full form:
|
which is in turn equivalent of the full form:
|
||||||
```php
|
```php
|
||||||
'fields' => [
|
'fields' => [
|
||||||
['name' => 'id', 'type' => Type::id()],
|
['name' => 'id', 'type' => Type::id()],
|
||||||
@ -124,11 +124,15 @@ Same shorthand notation applies to field arguments as well.
|
|||||||
Almost all real-world applications contain recurring or circular types.
|
Almost all real-world applications contain recurring or circular types.
|
||||||
Think user friends or nested comments for example.
|
Think user friends or nested comments for example.
|
||||||
|
|
||||||
**graphql-php** allows such types, but you have to use `callback` in
|
**graphql-php** allows such types, but you have to use `callable` in
|
||||||
option **fields** (and/or **interfaces**).
|
option **fields** (and/or **interfaces**).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
|
||||||
$userType = null;
|
$userType = null;
|
||||||
|
|
||||||
$userType = new ObjectType([
|
$userType = new ObjectType([
|
||||||
@ -193,14 +197,14 @@ class MyTypes
|
|||||||
|
|
||||||
# Field Resolution
|
# Field Resolution
|
||||||
Field resolution is the primary mechanism in **graphql-php** for returning actual data for your fields.
|
Field resolution is the primary mechanism in **graphql-php** for returning actual data for your fields.
|
||||||
It is implemented using `resolveField` callable in type definition or `resolve`
|
It is implemented using **resolveField** callable in type definition or **resolve**
|
||||||
callable in field definition (which has precedence).
|
callable in field definition (which has precedence).
|
||||||
|
|
||||||
Read section on [Data Fetching](../data-fetching.md) for complete description of this process.
|
Read the section on [Data Fetching](../data-fetching.md) for a complete description of this process.
|
||||||
|
|
||||||
# Custom Metadata
|
# Custom Metadata
|
||||||
All types in **graphql-php** accept configuration array. In some cases you may be interested in
|
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.
|
passing your own metadata for type or field definition.
|
||||||
|
|
||||||
**graphql-php** preserves original configuration array in every type or field instance in
|
**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.
|
public property **$config**. Use it to implement app-level mappings and definitions.
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
# Built-in Scalar Types
|
# Built-in Scalar Types
|
||||||
GraphQL specification describes several built-in scalar types. In **graphql-php** they are
|
GraphQL specification describes several built-in scalar types. In **graphql-php** they are
|
||||||
exposed as static methods of `GraphQL\Type\Definition\Type` class:
|
exposed as static methods of [`GraphQL\Type\Definition\Type`](../reference.md#graphqltypedefinitiontype) class:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
|
||||||
// Built-in Scalar types:
|
// Built-in Scalar types:
|
||||||
@ -12,30 +13,30 @@ Type::float(); // Float type
|
|||||||
Type::boolean(); // Boolean type
|
Type::boolean(); // Boolean type
|
||||||
Type::id(); // ID type
|
Type::id(); // ID type
|
||||||
```
|
```
|
||||||
Those methods return instances of `GraphQL\Type\Definition\ScalarType` (actually one of it subclasses).
|
Those methods return instances of `GraphQL\Type\Definition\ScalarType` (actually one of subclasses).
|
||||||
Use them directly in type definitions, or wrap in your [TypeRegistry](index.md#type-registry)
|
Use them directly in type definitions, or wrap in your [TypeRegistry](index.md#type-registry)
|
||||||
(if you use one).
|
(if you use one).
|
||||||
|
|
||||||
# Writing Custom Scalar Types
|
# Writing Custom Scalar Types
|
||||||
In addition to built-in scalars, you can define your own scalar types with additional validation.
|
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.
|
Typical examples of such types are **Email**, **Date**, **Url**, etc.
|
||||||
|
|
||||||
In order to implement your own type you must understand how scalars are presented in GraphQL.
|
In order to implement your own type, you must understand how scalars are presented in GraphQL.
|
||||||
GraphQL deals with scalars in following cases:
|
GraphQL deals with scalars in following cases:
|
||||||
|
|
||||||
1. When converting **internal representation** of value returned by your app (e.g. stored in database
|
1. When converting **internal representation** of value returned by your app (e.g. stored in a database
|
||||||
or hardcoded in source code) to **serialized** representation included in response.
|
or hardcoded in the source code) to **serialized** representation included in the response.
|
||||||
|
|
||||||
2. When converting **input value** passed by client in variables along with GraphQL query to
|
2. When converting **input value** passed by a client in variables along with GraphQL query to
|
||||||
**internal representation** of your app.
|
**internal representation** of your app.
|
||||||
|
|
||||||
3. When converting **input literal value** hardcoded in GraphQL query (e.g. field argument value) to
|
3. When converting **input literal value** hardcoded in GraphQL query (e.g. field argument value) to
|
||||||
**internal representation** of your app.
|
the **internal representation** of your app.
|
||||||
|
|
||||||
Those cases are covered by methods `serialize`, `parseValue` and `parseLiteral` of abstract `ScalarType`
|
Those cases are covered by methods `serialize`, `parseValue` and `parseLiteral` of abstract `ScalarType`
|
||||||
class respectively.
|
class respectively.
|
||||||
|
|
||||||
Here is an example of simple `Email` type:
|
Here is an example of a simple **Email** type:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
# Schema Definition
|
# Schema Definition
|
||||||
Schema is a container of your type hierarchy, which accepts root types in constructor and provides
|
The schema is a container of your type hierarchy, which accepts root types in a constructor and provides
|
||||||
methods for receiving information about your types to internal GrahpQL tools.
|
methods for receiving information about your types to internal GrahpQL tools.
|
||||||
|
|
||||||
In **graphql-php** schema is an instance of [`GraphQL\Type\Schema`](../reference.md#graphqltypeschema)
|
In **graphql-php** schema is an instance of [`GraphQL\Type\Schema`](../reference.md#graphqltypeschema)
|
||||||
which accepts configuration array in constructor:
|
which accepts configuration array in a constructor:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
|
|
||||||
$schema = new Schema([
|
$schema = new Schema([
|
||||||
@ -16,18 +17,18 @@ $schema = new Schema([
|
|||||||
See possible constructor options [below](#configuration-options).
|
See possible constructor options [below](#configuration-options).
|
||||||
|
|
||||||
# Query and Mutation types
|
# Query and Mutation types
|
||||||
Schema consists of two root types:
|
The schema consists of two root types:
|
||||||
|
|
||||||
* `Query` type is a surface of your read API
|
* **Query** type is a surface of your read API
|
||||||
* `Mutation` type (optional) exposes write API by declaring all possible mutations in your app.
|
* **Mutation** type (optional) exposes write API by declaring all possible mutations in your app.
|
||||||
|
|
||||||
Query and Mutation types are regular [object types](object-types.md) containing root-level fields
|
Query and Mutation types are regular [object types](object-types.md) containing root-level fields
|
||||||
of your API:
|
of your API:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema;
|
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
$queryType = new ObjectType([
|
||||||
'name' => 'Query',
|
'name' => 'Query',
|
||||||
@ -37,7 +38,7 @@ $queryType = new ObjectType([
|
|||||||
'resolve' => function() {
|
'resolve' => function() {
|
||||||
return 'Hello World!';
|
return 'Hello World!';
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
'hero' => [
|
'hero' => [
|
||||||
'type' => $characterInterface,
|
'type' => $characterInterface,
|
||||||
'args' => [
|
'args' => [
|
||||||
@ -55,8 +56,8 @@ $queryType = new ObjectType([
|
|||||||
$mutationType = new ObjectType([
|
$mutationType = new ObjectType([
|
||||||
'name' => 'Mutation',
|
'name' => 'Mutation',
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'createReviewForEpisode' => [
|
'createReview' => [
|
||||||
'type' => $createReviewForEpisodeMutation,
|
'type' => $createReviewOutput,
|
||||||
'args' => [
|
'args' => [
|
||||||
'episode' => $episodeEnum,
|
'episode' => $episodeEnum,
|
||||||
'review' => $reviewInputObject
|
'review' => $reviewInputObject
|
||||||
@ -69,13 +70,13 @@ $mutationType = new ObjectType([
|
|||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep in mind that other than the special meaning of declaring surface area of your API,
|
Keep in mind that other than the special meaning of declaring a surface area of your API,
|
||||||
those types are the same as any other [object type](object-types.md), and their fields work
|
those types are the same as any other [object type](object-types.md), and their fields work
|
||||||
exactly the same way.
|
exactly the same way.
|
||||||
|
|
||||||
**Mutation** type is also just a regular object type. The difference is in semantics.
|
**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
|
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.md) for details).
|
with complex input values (see [Mutations and Input Types](input-types.md) for details).
|
||||||
|
|
||||||
# Configuration Options
|
# Configuration Options
|
||||||
Schema constructor expects an instance of [`GraphQL\Type\SchemaConfig`](../reference.md#graphqltypeschemaconfig)
|
Schema constructor expects an instance of [`GraphQL\Type\SchemaConfig`](../reference.md#graphqltypeschemaconfig)
|
||||||
@ -86,14 +87,15 @@ Option | Type | Notes
|
|||||||
query | `ObjectType` | **Required.** Object type (usually named "Query") containing root-level fields of your read API
|
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
|
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)
|
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.md) 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::getStandardDirectives(), [$myCustomDirective]`
|
directives | `Directive[]` | A full list of [directives](directives.md) 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:<br><br> *array_merge(GraphQL::getStandardDirectives(), [$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.
|
types | `ObjectType[]` | List of object types which cannot be detected by **graphql-php** during static schema analysis.<br><br>Most often it happens when the object type is never referenced in fields directly but is still a part of a schema because it implements an interface which resolves to this object type in its **resolveType** callable. <br><br> Note that you are not required to pass all of your types here - it is simply a workaround for concrete use-case.
|
||||||
|
typeLoader | `callable` | **function($name)** Expected to return type instance given the name. Must always return the same instance if called multiple times. See section below on lazy type loading.
|
||||||
|
|
||||||
# Lazy loading of types
|
# Lazy loading of types
|
||||||
By default a schema will scan all of your type and field definitions to serve GraphQL queries.
|
By default, the schema will scan all of your type, field and argument definitions to serve GraphQL queries.
|
||||||
It may cause performance overhead when there are many types in a schema.
|
It may cause performance overhead when there are many types in the schema.
|
||||||
|
|
||||||
In this case it is recommended to pass **typeLoader** option to schema constructor and define all
|
In this case, it is recommended to pass **typeLoader** option to schema constructor and define all
|
||||||
of your object **fields** as callbacks.
|
of your object **fields** as callbacks.
|
||||||
|
|
||||||
Type loading concept is very similar to PHP class loading, but keep in mind that **typeLoader** must
|
Type loading concept is very similar to PHP class loading, but keep in mind that **typeLoader** must
|
||||||
@ -101,9 +103,13 @@ always return the same instance of a type.
|
|||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Schema;
|
||||||
|
|
||||||
class Types
|
class Types
|
||||||
{
|
{
|
||||||
private $registry = [];
|
private $types = [];
|
||||||
|
|
||||||
public function get($name)
|
public function get($name)
|
||||||
{
|
{
|
||||||
@ -143,11 +149,11 @@ $schema = new Schema([
|
|||||||
|
|
||||||
|
|
||||||
# Schema Validation
|
# Schema Validation
|
||||||
By default schema is created with only shallow validation of type and field definitions
|
By default, the schema is created with only shallow validation of type and field definitions
|
||||||
(because validation requires full schema scan and is very costly on bigger schemas).
|
(because validation requires full schema scan and is very costly on bigger schemas).
|
||||||
|
|
||||||
But there is a special method `$schema->assertValid()` which throws `GraphQL\Error\InvariantViolation`
|
But there is a special method **assertValid()** on schema instance which throws
|
||||||
exception when it encounters any error, like:
|
`GraphQL\Error\InvariantViolation` exception when it encounters any error, like:
|
||||||
|
|
||||||
- Invalid types used for fields/arguments
|
- Invalid types used for fields/arguments
|
||||||
- Missing interface implementations
|
- Missing interface implementations
|
||||||
@ -159,11 +165,11 @@ Don't call it in web requests in production.
|
|||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
try {
|
||||||
$schema = new GraphQL\Type\Schema([
|
$schema = new GraphQL\Type\Schema([
|
||||||
'query' => $myQueryType
|
'query' => $myQueryType
|
||||||
]);
|
]);
|
||||||
|
|
||||||
try {
|
|
||||||
$schema->assertValid();
|
$schema->assertValid();
|
||||||
} catch (GraphQL\Error\InvariantViolation $e) {
|
} catch (GraphQL\Error\InvariantViolation $e) {
|
||||||
echo $e->getMessage();
|
echo $e->getMessage();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
[Type language](http://graphql.org/learn/schema/#type-language) is a convenient way to define your schema,
|
[Type language](http://graphql.org/learn/schema/#type-language) is a convenient way to define your schema,
|
||||||
especially with IDE autocompletion and syntax validation.
|
especially with IDE autocompletion and syntax validation.
|
||||||
|
|
||||||
Here is a simple schema defined in GraphQL type language (e.g. in separate **schema.graphql** file):
|
Here is a simple schema defined in GraphQL type language (e.g. in a separate **schema.graphql** file):
|
||||||
|
|
||||||
```graphql
|
```graphql
|
||||||
schema {
|
schema {
|
||||||
@ -21,7 +21,8 @@ input HelloInput {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In order to create schema instance out of this file, use `GraphQL\Utils\BuildSchema`:
|
In order to create schema instance out of this file, use
|
||||||
|
[`GraphQL\Utils\BuildSchema`](../reference.md#graphqlutilsbuildschema):
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
@ -31,19 +32,19 @@ $contents = file_get_contents('schema.graphql');
|
|||||||
$schema = BuildSchema::build($contents);
|
$schema = BuildSchema::build($contents);
|
||||||
```
|
```
|
||||||
|
|
||||||
By default such schema is created without any resolvers. As a result it doesn't support **Interfaces** and **Unions**
|
By default, such schema is created without any resolvers. As a result, it doesn't support **Interfaces** and **Unions**
|
||||||
because it is impossible to resolve actual implementations during execution.
|
because it is impossible to resolve actual implementations during execution.
|
||||||
|
|
||||||
Also we have to rely on [default field resolver](../data-fetching.md#default-field-resolver) and **root value** in
|
Also, we have to rely on [default field resolver](../data-fetching.md#default-field-resolver) and **root value** in
|
||||||
order to execute query against this schema.
|
order to execute a query against this schema.
|
||||||
|
|
||||||
# Defining resolvers
|
# Defining resolvers
|
||||||
In order to enable **Interfaces**, **Unions** and custom field resolvers you can pass second argument:
|
In order to enable **Interfaces**, **Unions** and custom field resolvers you can pass the second argument:
|
||||||
**type config decorator** to schema builder.
|
**type config decorator** to schema builder.
|
||||||
|
|
||||||
It accepts default type config produced by builder and is expected to add missing options like
|
It accepts default type config produced by the builder and is expected to add missing options like
|
||||||
[`resolveType`](interfaces.md#configuration-options) for interface types or
|
[**resolveType**](interfaces.md#configuration-options) for interface types or
|
||||||
[`resolveField`](object-types.md#configuration-options) for object types.
|
[**resolveField**](object-types.md#configuration-options) for object types.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
@ -60,17 +61,17 @@ $schema = BuildSchema::build($contents, $typeConfigDecorator);
|
|||||||
```
|
```
|
||||||
|
|
||||||
# Performance considerations
|
# Performance considerations
|
||||||
Method `BuildSchema::build()` produces a [lazy schema](schema.md#lazy-loading-of-types)
|
Method **build()** produces a [lazy schema](schema.md#lazy-loading-of-types)
|
||||||
automatically, so it works efficiently even with very large schemas.
|
automatically, so it works efficiently even with very large schemas.
|
||||||
|
|
||||||
But parsing type definition file on each request is suboptimal, so it is recommended to cache
|
But parsing type definition file on each request is suboptimal, so it is recommended to cache
|
||||||
intermediate parsed representation of the schema for production environment:
|
intermediate parsed representation of the schema for the production environment:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Utils\BuildSchema;
|
use GraphQL\Utils\BuildSchema;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Utils\AST;
|
||||||
|
|
||||||
$cacheFilename = 'cached_schema.php';
|
$cacheFilename = 'cached_schema.php';
|
||||||
|
|
||||||
@ -78,7 +79,7 @@ if (!file_exists($cacheFilename)) {
|
|||||||
$document = Parser::parse(file_get_contents('./schema.graphql'));
|
$document = Parser::parse(file_get_contents('./schema.graphql'));
|
||||||
file_put_contents($cacheFilename, "<?php\nreturn " . var_export($document->toArray(), true));
|
file_put_contents($cacheFilename, "<?php\nreturn " . var_export($document->toArray(), true));
|
||||||
} else {
|
} else {
|
||||||
$document = Node::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well
|
$document = AST::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well
|
||||||
}
|
}
|
||||||
|
|
||||||
$typeConfigDecorator = function () {};
|
$typeConfigDecorator = function () {};
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
# Union Type Definition
|
# Union Type Definition
|
||||||
A Union is an abstract type that simply enumerates other Object Types.
|
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.
|
The 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`
|
In **graphql-php** union type is an instance of `GraphQL\Type\Definition\UnionType`
|
||||||
(or one of it subclasses) which accepts configuration array in constructor:
|
(or one of its subclasses) which accepts configuration array in a constructor:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
<?php
|
||||||
|
use GraphQL\Type\Definition\UnionType;
|
||||||
|
|
||||||
$searchResultType = new UnionType([
|
$searchResultType = new UnionType([
|
||||||
'name' => 'SearchResult',
|
'name' => 'SearchResult',
|
||||||
'types' => [
|
'types' => [
|
||||||
MyTypes::story(),
|
MyTypes::story(),
|
||||||
MyTypes::user()
|
MyTypes::user()
|
||||||
];
|
],
|
||||||
'resolveType' => function($value) {
|
'resolveType' => function($value) {
|
||||||
if ($value->type === 'story') {
|
if ($value->type === 'story') {
|
||||||
return MyTypes::story();
|
return MyTypes::story();
|
||||||
@ -26,11 +29,11 @@ This example uses **inline** style for Union definition, but you can also use
|
|||||||
[inheritance or type language](index.md#type-definition-styles).
|
[inheritance or type language](index.md#type-definition-styles).
|
||||||
|
|
||||||
# Configuration options
|
# Configuration options
|
||||||
Constructor of UnionType accepts an array. Below is a full list of allowed options:
|
The constructor of UnionType accepts an array. Below is a full list of allowed options:
|
||||||
|
|
||||||
Option | Type | Notes
|
Option | Type | Notes
|
||||||
------ | ---- | -----
|
------ | ---- | -----
|
||||||
name | `string` | **Required.** Unique name of this interface type within Schema
|
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.
|
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)
|
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`.
|
resolveType | `callback` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**<br> Receives **$value** from resolver of the parent field and returns concrete Object Type for this **$value**.
|
||||||
|
@ -11,7 +11,7 @@ pages:
|
|||||||
- Lists and Non-Null: type-system/lists-and-nonnulls.md
|
- Lists and Non-Null: type-system/lists-and-nonnulls.md
|
||||||
- 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
|
- Mutations and Input Types: type-system/input-types.md
|
||||||
- Directives: type-system/directives.md
|
- Directives: type-system/directives.md
|
||||||
- Schema: type-system/schema.md
|
- Schema: type-system/schema.md
|
||||||
- Using Type Language: type-system/type-language.md
|
- Using Type Language: type-system/type-language.md
|
||||||
|
Loading…
Reference in New Issue
Block a user