mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-21 20:36:05 +03:00
Further documentation improvements
This commit is contained in:
parent
2537a62ec2
commit
637156fe65
14
UPGRADE.md
14
UPGRADE.md
@ -1,6 +1,6 @@
|
||||
## Upgrade v0.8.x, v0.9.x > v0.10.x
|
||||
|
||||
### Breaking: minimum PHP version was changed from 5.4 to 5.5
|
||||
### Breaking: changed minimum PHP version from 5.4 to 5.5
|
||||
It allows us to leverage `::class` constant, `generators` and other features of newer PHP versions.
|
||||
|
||||
### Breaking: default error formatting
|
||||
@ -71,8 +71,9 @@ to adjust if you were checking for this error in your custom error formatters.
|
||||
### Breaking: removed previously deprecated ability to define type as callable
|
||||
See https://github.com/webonyx/graphql-php/issues/35
|
||||
|
||||
### Deprecated: `GraphQL\GraphQL::executeAndReturnResult` renamed to `GraphQL\GraphQL::executeQuery`
|
||||
Old method name is still available, but will trigger deprecation warning in next version.
|
||||
### Deprecated: `GraphQL\GraphQL::executeAndReturnResult`
|
||||
Method is renamed to `GraphQL\GraphQL::executeQuery`. Old method name is still available,
|
||||
but will trigger deprecation warning in the next version.
|
||||
|
||||
### Deprecated: `GraphQL\GraphQL::execute`
|
||||
Use `GraphQL\GraphQL::executeQuery()->toArray()` instead.
|
||||
@ -95,6 +96,13 @@ $schema->assertValid();
|
||||
```
|
||||
See https://github.com/webonyx/graphql-php/issues/148
|
||||
|
||||
### Non-breaking: usage on async platforms
|
||||
When using the library on async platforms use separate method `GraphQL::promiseToExecute()`.
|
||||
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,
|
||||
but they are deprecated and will be removed eventually.
|
||||
|
||||
## Upgrade v0.7.x > v0.8.x
|
||||
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.
|
||||
|
@ -3,10 +3,10 @@ GraphQL is data-storage agnostic. You can use any underlying data storage engine
|
||||
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
|
||||
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/#field-configuration-options) or [query execution call](executing-queries/#overview).
|
||||
|
||||
Result returned by `resolve` function is directly included in response (for scalars and enums)
|
||||
Result returned by **resolve** function is directly included in response (for scalars and enums)
|
||||
or passed down to nested fields (for objects).
|
||||
|
||||
Let's walk through an example. Consider following GraphQL query:
|
||||
@ -22,7 +22,7 @@ Let's walk through an example. Consider following GraphQL query:
|
||||
}
|
||||
```
|
||||
|
||||
We need Schema that can fulfill it. On the very top level Schema contains Query type:
|
||||
We need a Schema that can fulfill it. On the very top level the Schema contains Query type:
|
||||
|
||||
```php
|
||||
$queryType = new ObjectType([
|
||||
@ -44,12 +44,12 @@ $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
|
||||
your database/cache/search index and return result.
|
||||
|
||||
Since `lastStory` is of complex 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
|
||||
$blogStoryType = new ObjectType([
|
||||
@ -81,15 +81,15 @@ $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 real-world applications you would fetch user data from datastore 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
|
||||
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?
|
||||
|
||||
The answer is: there is default resolver for all fields. When you define your own `resolve` function
|
||||
There is a default resolver for all fields. When you define your own **resolve** function
|
||||
for a field you simply override this default resolver.
|
||||
|
||||
# Default Field Resolver
|
||||
@ -114,12 +114,10 @@ function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
|
||||
}
|
||||
```
|
||||
|
||||
As you see it returns value by key (for arrays) or property (for objects). If value is not set - it returns `null`.
|
||||
As you see it returns value by key (for arrays) or property (for objects).
|
||||
If value is not set - it returns **null**.
|
||||
|
||||
To override default resolver - use:
|
||||
```php
|
||||
GraphQL\GraphQL::setDefaultFieldResolver($myResolverCallback);
|
||||
```
|
||||
To override the default resolver, pass it as an argument of [executeQuery](executing-queries) call.
|
||||
|
||||
# Default Field Resolver per Type
|
||||
Sometimes it might be convenient to set default field resolver per type. You can do so by providing
|
||||
@ -154,8 +152,8 @@ Keep in mind that **field resolver** has precedence over **default field resolve
|
||||
# Solving N+1 Problem
|
||||
Since: 0.9.0
|
||||
|
||||
One of the most annoying problems with data fetching is so-called [N+1 problem](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/).
|
||||
|
||||
One of the most annoying problems with data fetching is a so-called
|
||||
[N+1 problem](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/). <br>
|
||||
Consider following GraphQL query:
|
||||
```
|
||||
{
|
||||
@ -219,28 +217,41 @@ In this example only one query will be executed for all story authors comparing
|
||||
in naive implementation.
|
||||
|
||||
# Async PHP
|
||||
Since: 0.9.0
|
||||
Since: 0.10.0 (version 0.9.0 had slightly different API which is deprecated)
|
||||
|
||||
If your project runs in environment that supports async operations
|
||||
(like `HHVM`, `ReactPHP`, `Icicle.io`, `appserver.io` `PHP threads`, etc) you can leverage
|
||||
the power of your platform to resolve fields asynchronously.
|
||||
(like HHVM, ReactPHP, Icicle.io, appserver.io, PHP threads, etc)
|
||||
you can leverage the power of your platform to resolve some fields asynchronously.
|
||||
|
||||
The only requirement: your platform must support the concept of Promises compatible with
|
||||
[Promises A+](https://promisesaplus.com/) specification.
|
||||
|
||||
To enable async support - set adapter for promises:
|
||||
```
|
||||
GraphQL\GraphQL::setPromiseAdapter($adapter);
|
||||
To start using this feature, switch facade method for query execution from
|
||||
**executeQuery** to **promiseToExecute**:
|
||||
|
||||
```php
|
||||
$promise = GraphQL::promiseToExecute(
|
||||
$promiseAdapter,
|
||||
$schema,
|
||||
$queryString,
|
||||
$rootValue = null,
|
||||
$contextValue = null,
|
||||
$variableValues = null,
|
||||
$operationName = null,
|
||||
$fieldResolver = null,
|
||||
$validationRules = null
|
||||
);
|
||||
$promise->then(function(ExecutionResult $result) {
|
||||
return $result->toArray();
|
||||
});
|
||||
```
|
||||
|
||||
Where `$adapter` is an instance of class implementing `GraphQL\Executor\Promise\PromiseAdapter` interface.
|
||||
Where **$promiseAdapter** is an instance of:
|
||||
|
||||
Then in your `resolve` functions you should return `Promises` of your platform instead of
|
||||
`GraphQL\Deferred` instances.
|
||||
* For [ReactPHP](https://github.com/reactphp/react) (requires **react/promise** as composer dependency): <br>
|
||||
`GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter`
|
||||
|
||||
Platforms supported out of the box:
|
||||
* Other platforms: write your own class implementing interface: <br>
|
||||
`GraphQL\Executor\Promise\PromiseAdapter`.
|
||||
|
||||
* [ReactPHP](https://github.com/reactphp/react) (requires **react/promise** as composer dependency):
|
||||
`GraphQL\GraphQL::setPromiseAdapter(new GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter());`
|
||||
|
||||
To integrate other platform - implement `GraphQL\Executor\Promise\PromiseAdapter` interface.
|
||||
Then your **resolve** functions should return promises of your platform instead of `GraphQL\Deferred`s.
|
@ -48,4 +48,7 @@ Schema Language parser.
|
||||
Ready for real-world usage.
|
||||
|
||||
## Github
|
||||
Project source code is [hosted on GitHub](https://github.com/webonyx/graphql-php).
|
||||
Project source code is [hosted on GitHub](https://github.com/webonyx/graphql-php).
|
||||
|
||||
## Framework Integrations
|
||||
Read the section about [Complementary tools](complementary-tools/).
|
@ -21,8 +21,7 @@ class GraphQL
|
||||
$variableValues = null,
|
||||
$operationName = null,
|
||||
callable $fieldResolver = null,
|
||||
array $validationRules = null,
|
||||
GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter = null
|
||||
array $validationRules = null
|
||||
);
|
||||
|
||||
/**
|
||||
@ -502,22 +501,20 @@ use GraphQL\Executor\Promise\PromiseAdapter;
|
||||
class Executor
|
||||
{
|
||||
/**
|
||||
* Executes DocumentNode against given schema.
|
||||
* Executes DocumentNode against given $schema using given $promiseAdapter for deferred resolvers.
|
||||
* Returns promise which is always fullfilled with instance of ExecutionResult
|
||||
*
|
||||
* When $promiseAdapter is passed returns Promise instance produced by this adapter.
|
||||
* By default simply returns ExecutionResult
|
||||
*
|
||||
* @return ExecutionResult|Promise
|
||||
* @return Promise
|
||||
*/
|
||||
public static function execute(
|
||||
public static function promiseToExecute(
|
||||
PromiseAdapter $promiseAdapter,
|
||||
Schema $schema,
|
||||
DocumentNode $ast,
|
||||
$rootValue = null,
|
||||
$contextValue = null,
|
||||
$variableValues = null,
|
||||
$operationName = null,
|
||||
callable $fieldResolver = null,
|
||||
PromiseAdapter $promiseAdapter = null
|
||||
callable $fieldResolver = null
|
||||
);
|
||||
}
|
||||
```
|
||||
@ -601,6 +598,80 @@ class ExecutionResult implements \JsonSerializable
|
||||
}
|
||||
```
|
||||
|
||||
# GraphQL\Executor\Promise\PromiseAdapter
|
||||
Required for [Async PHP](data-fetching/#async-php) only.
|
||||
|
||||
```php
|
||||
interface PromiseAdapter
|
||||
{
|
||||
/**
|
||||
* Return true if value is promise of underlying system
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isThenable($value);
|
||||
|
||||
/**
|
||||
* Converts thenable of underlying system into Promise instance
|
||||
*
|
||||
* @param object $thenable
|
||||
* @return Promise
|
||||
*/
|
||||
public function convertThenable($thenable);
|
||||
|
||||
/**
|
||||
* Accepts our Promise wrapper, extracts adopted promise out of it and executes actual `then` logic described
|
||||
* in Promises/A+ specs. Then returns new wrapped Promise instance.
|
||||
*
|
||||
* @param Promise $promise
|
||||
* @param callable|null $onFulfilled
|
||||
* @param callable|null $onRejected
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
public function then(Promise $promise, callable $onFulfilled = null, callable $onRejected = null);
|
||||
|
||||
/**
|
||||
* Creates a Promise
|
||||
*
|
||||
* @param callable $resolver
|
||||
|
||||
* @return Promise
|
||||
*/
|
||||
public function create(callable $resolver);
|
||||
|
||||
/**
|
||||
* Creates a fulfilled Promise for a value if the value is not a promise.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
public function createFulfilled($value = null);
|
||||
|
||||
/**
|
||||
* Creates a rejected promise for a reason if the reason is not a promise. If
|
||||
* the provided reason is a promise, then it is returned as-is.
|
||||
*
|
||||
* @param \Throwable $reason
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
public function createRejected($reason);
|
||||
|
||||
/**
|
||||
* Given an array of promises (or values), returns a promise that is fulfilled when all the
|
||||
* items in the array are fulfilled.
|
||||
*
|
||||
* @param array $promisesOrValues Promises or values.
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
public function all(array $promisesOrValues);
|
||||
}
|
||||
```
|
||||
|
||||
# GraphQL\Type\Definition\ResolveInfo
|
||||
|
||||
```php
|
||||
@ -910,3 +981,9 @@ class FormattedError
|
||||
public static function prepareFormatter(callable $formatter = null, $debug);
|
||||
}
|
||||
```
|
||||
|
||||
# GraphQL\Server\OperationParams
|
||||
|
||||
# GraphQL\Server\StandardServer
|
||||
|
||||
# GraphQL\Server\Helper
|
||||
|
@ -50,34 +50,26 @@ class MyType extends ObjectType
|
||||
}
|
||||
```
|
||||
|
||||
You can also mix-and-match styles for convenience. For example:
|
||||
```php
|
||||
<?php
|
||||
namespace MyApp;
|
||||
Using [GraphQL Type language](graphql.org/learn/schema/#type-language):
|
||||
|
||||
use GraphQL\Type\Definition\ObjectType;
|
||||
use GraphQL\Type\Definition\Type;
|
||||
```graphql
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
||||
|
||||
class BlogPostType extends ObjectType
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$config = [
|
||||
'fields' => [
|
||||
'body' => new ObjectType([
|
||||
'name' => 'BlogPostBody',
|
||||
'fields' => [
|
||||
'html' => Type::string(),
|
||||
'text' => Type::string(),
|
||||
]
|
||||
])
|
||||
]
|
||||
];
|
||||
parent::__construct($config);
|
||||
}
|
||||
type Query {
|
||||
greetings(input: HelloInput!): String!
|
||||
}
|
||||
|
||||
input HelloInput {
|
||||
firstName: String!
|
||||
lastName: String
|
||||
}
|
||||
```
|
||||
|
||||
[Read more](/type-system/type-language/) about it in a dedicated docs section.
|
||||
|
||||
# Type Registry
|
||||
Every type must be presented in Schema by single instance (**graphql-php**
|
||||
throws when it discovers several instances with the same `name` in schema).
|
||||
|
@ -42,6 +42,7 @@ Here is an example of simple `Email` type:
|
||||
namespace MyApp;
|
||||
|
||||
use GraphQL\Error\Error;
|
||||
use GraphQL\Error\InvariantViolation;
|
||||
use GraphQL\Language\AST\StringValueNode;
|
||||
use GraphQL\Type\Definition\ScalarType;
|
||||
use GraphQL\Utils\Utils;
|
||||
@ -62,9 +63,12 @@ class EmailType extends ScalarType
|
||||
{
|
||||
// Assuming internal representation of email is always correct:
|
||||
return $value;
|
||||
|
||||
// If it might be incorrect and you want to make sure that only correct values are included in response -
|
||||
// use following line instead:
|
||||
|
||||
// If it might be incorrect and you want to make sure that only correct values are included
|
||||
// in response - use following line instead:
|
||||
// if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||
// throw new InvariantViolation("Could not serialize following value as email: " . Utils::printSafe($value));
|
||||
// }
|
||||
// return $this->parseValue($value);
|
||||
}
|
||||
|
||||
@ -77,7 +81,7 @@ class EmailType extends ScalarType
|
||||
public function parseValue($value)
|
||||
{
|
||||
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||
throw new \UnexpectedValueException("Cannot represent value as email: " . Utils::printSafe($value));
|
||||
throw new Error("Cannot represent following value as email: " . Utils::printSafeJson($value));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
@ -15,12 +15,11 @@ pages:
|
||||
- Schema: type-system/schema.md
|
||||
- Using Type Language: type-system/type-language.md
|
||||
- Executing Queries: executing-queries.md
|
||||
- Fetching Data: data-fetching.md
|
||||
- Fetching Data (resolving fields): data-fetching.md
|
||||
- Handling Errors: error-handling.md
|
||||
# - Mutations: mutations.md
|
||||
# - Security: security.md
|
||||
# - Performance tips: performance.md
|
||||
# - Standard Server: server.md
|
||||
- How it works: how-it-works.md
|
||||
- Class Reference: reference.md
|
||||
- Complementary Tools: complementary-tools.md
|
||||
|
Loading…
Reference in New Issue
Block a user