Deployed df1b575 with MkDocs version: 0.16.3

This commit is contained in:
Vladimir Razuvaev 2017-08-20 23:28:59 +07:00
parent b48875693c
commit 6db489f066
23 changed files with 4813 additions and 604 deletions

View File

@ -57,9 +57,23 @@
<a class="" href="../getting-started/">Getting Started</a>
</li>
<li class="toctree-l1 current">
<a class="current" href="./">Complementary Tools</a>
<ul class="subnav">
<li class="toctree-l2"><a href="#integrations">Integrations</a></li>
<li class="toctree-l2"><a href="#tools">Tools</a></li>
</ul>
</li>
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +105,7 @@
</li>
<li class="">
<a class="" href="../type-system/input-types/">Input Types</a>
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -101,6 +115,10 @@
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -119,18 +137,19 @@
<a class="" href="../error-handling/">Handling Errors</a>
</li>
<li class="toctree-l1 current">
<li class="toctree-l1">
<a class="current" href="./">Complementary Tools</a>
<ul class="subnav">
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l2"><a href="#integrations">Integrations</a></li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l2"><a href="#tools">Tools</a></li>
<li class="toctree-l1">
</ul>
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -170,6 +189,8 @@
<li><a href="https://github.com/ivome/graphql-relay-php">Integration with Relay</a></li>
<li><a href="https://github.com/Folkloreatelier/laravel-graphql">Integration with Laravel 5</a> + <a href="https://github.com/nuwave/laravel-graphql-relay">Relay Helpers for Laravel</a></li>
<li><a href="https://github.com/overblog/GraphQLBundle">Symfony Bundle</a> by Overblog</li>
<li>Define types with Doctrine ORM annotations (<a href="https://github.com/Ecodev/graphql-doctrine">for PHP7.1</a>, for <a href="https://github.com/rahuljayaraman/doctrine-graphql">earlier PHP versions</a>)</li>
<li>Out of the box integration with any PSR-7 compatible framework (like <a href="http://slimframework.com">Slim</a> or <a href="http://zendframework.github.io/zend-expressive/">Zend Expressive</a>) via <a href="../executing-queries.md/#using-server">Standard Server</a></li>
</ul>
<h1 id="tools">Tools</h1>
<ul>
@ -177,6 +198,7 @@
<li><a href="https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij">ChromeiQL</a>
or <a href="https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp">GraphiQL Feen</a> -
GraphiQL as Google Chrome extension</li>
<li><a href="https://github.com/overblog/dataloader-php">DataLoader PHP</a> - as a ready implementation for <a href="../data-fetching/#solving-n1-problem">deferred resolvers</a></li>
</ul>
</div>
@ -185,8 +207,10 @@
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../type-system/" class="btn btn-neutral float-right" title="Introduction">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../error-handling/" class="btn btn-neutral" title="Handling Errors"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../getting-started/" class="btn btn-neutral" title="Getting Started"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
@ -212,9 +236,11 @@
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../error-handling/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span><a href="../getting-started/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../type-system/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../js/theme.js"></script>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +96,7 @@
</li>
<li class="">
<a class="" href="../type-system/input-types/">Input Types</a>
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -101,6 +106,10 @@
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -139,7 +148,17 @@
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -177,10 +196,10 @@
<h1 id="overview">Overview</h1>
<p>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.</p>
<p>In order to convert GraphQL query to PHP array <strong>graphql-php</strong> traverses query fields (using depth-first algorithm) and
runs special <code>resolve</code> function on each field. This <code>resolve</code> function is provided by you as a part of
<a href="../type-system/object-types/#field-configuration-options">field definition</a>.</p>
<p>Result returned by <code>resolve</code> function is directly included in response (for scalars and enums)
<p>In order to convert the GraphQL query to PHP array, <strong>graphql-php</strong> traverses query fields (using depth-first algorithm) and
runs special <strong>resolve</strong> function on each field. This <strong>resolve</strong> function is provided by you as a part of
<a href="../type-system/object-types/#field-configuration-options">field definition</a> or <a href="../executing-queries/#overview">query execution call</a>.</p>
<p>Result returned by <strong>resolve</strong> function is directly included in the response (for scalars and enums)
or passed down to nested fields (for objects).</p>
<p>Let's walk through an example. Consider following GraphQL query:</p>
<pre><code class="graphql">{
@ -193,8 +212,11 @@ or passed down to nested fields (for objects).</p>
}
</code></pre>
<p>We need Schema that can fulfill it. On the very top level Schema contains Query type:</p>
<pre><code class="php">$queryType = new ObjectType([
<p>We need a Schema that can fulfill it. On the very top level the Schema contains Query type:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\ObjectType;
$queryType = new ObjectType([
'name' =&gt; 'Query',
'fields' =&gt; [
@ -213,11 +235,15 @@ or passed down to nested fields (for objects).</p>
]);
</code></pre>
<p>As we see field <code>lastStory</code> has <code>resolve</code> function that is responsible for fetching data.</p>
<p>In our example we simply return array value, but in real-world application you would query
your database/cache/search index and return result.</p>
<p>Since <code>lastStory</code> is of complex type <code>BlogStory</code> this result is passed down to fields of this type:</p>
<pre><code class="php">$blogStoryType = new ObjectType([
<p>As we see field <strong>lastStory</strong> has <strong>resolve</strong> function that is responsible for fetching data.</p>
<p>In our example, we simply return array value, but in the real-world application you would query
your database/cache/search index and return the result.</p>
<p>Since <strong>lastStory</strong> is of composite type <strong>BlogStory</strong> this result is passed down to fields of this type:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$blogStoryType = new ObjectType([
'name' =&gt; 'BlogStory',
'fields' =&gt; [
@ -246,16 +272,17 @@ your database/cache/search index and return result.</p>
]);
</code></pre>
<p>Here <code>$blogStory</code> is the array returned by <code>lastStory</code> field above. </p>
<p>Again: in real-world applications you would fetch user data from datastore by <code>authorId</code> and return it.
Also note that you don't have to return arrays. You can return any value, <strong>graphql-php</strong> will pass it untouched
<p>Here <strong>$blogStory</strong> is the array returned by <strong>lastStory</strong> field above. </p>
<p>Again: in the real-world applications you would fetch user data from data store by <strong>authorId</strong> and return it.
Also, note that you don't have to return arrays. You can return any value, <strong>graphql-php</strong> will pass it untouched
to nested resolvers.</p>
<p>But then the question appears - field <code>title</code> has no <code>resolve</code> option. How is it resolved?</p>
<p>The answer is: there is default resolver for all fields. When you define your own <code>resolve</code> function
<p>But then the question appears - field <strong>title</strong> has no <strong>resolve</strong> option. How is it resolved?</p>
<p>There is a default resolver for all fields. When you define your own <strong>resolve</strong> function
for a field you simply override this default resolver.</p>
<h1 id="default-field-resolver">Default Field Resolver</h1>
<p><strong>graphql-php</strong> provides following default field resolver:</p>
<pre><code class="php">function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
<pre><code class="php">&lt;?php
function defaultFieldResolver($source, $args, $context, \GraphQL\Type\Definition\ResolveInfo $info)
{
$fieldName = $info-&gt;fieldName;
$property = null;
@ -274,15 +301,18 @@ for a field you simply override this default resolver.</p>
}
</code></pre>
<p>As you see it returns value by key (for arrays) or property (for objects). If value is not set - it returns <code>null</code>.</p>
<p>To override default resolver - use:</p>
<pre><code class="php">GraphQL\GraphQL::setDefaultFieldResolver($myResolverCallback);
</code></pre>
<p>As you see it returns value by key (for arrays) or property (for objects).
If the value is not set - it returns <strong>null</strong>.</p>
<p>To override the default resolver, pass it as an argument of <a href="../executing-queries/">executeQuery</a> call.</p>
<h1 id="default-field-resolver-per-type">Default Field Resolver per Type</h1>
<p>Sometimes it might be convenient to set default field resolver per type. You can do so by providing
<a href="../type-system/object-types/#configuration-options">resolveField option in type config</a>. For example:</p>
<pre><code class="php">$userType = new ObjectType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;
$userType = new ObjectType([
'name' =&gt; 'User',
'fields' =&gt; [
@ -307,8 +337,9 @@ for a field you simply override this default resolver.</p>
has precedence over <strong>default field resolver</strong>.</p>
<h1 id="solving-n1-problem">Solving N+1 Problem</h1>
<p>Since: 0.9.0</p>
<p>One of the most annoying problems with data fetching is so-called <a href="https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/">N+1 problem</a>.</p>
<p>Consider following GraphQL query:</p>
<p>One of the most annoying problems with data fetching is a so-called
<a href="https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/">N+1 problem</a>. <br>
Consider following GraphQL query:</p>
<pre><code>{
topStories(limit: 10) {
title
@ -320,11 +351,12 @@ for a field you simply override this default resolver.</p>
}
</code></pre>
<p>Naive field resolution process would require up to 10 calls to underlying data store to fetch authors for all 10 stories.</p>
<p><strong>graphql-php</strong> provides tools to mitigate this problem: it allows you to defer actual field resolution to later stage
<p>Naive field resolution process would require up to 10 calls to the underlying data store to fetch authors for all 10 stories.</p>
<p><strong>graphql-php</strong> 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.</p>
<p>Here is an example of <code>BlogStory</code> resolver for field <code>author</code> that uses deferring:</p>
<pre><code class="php">'resolve' =&gt; function($blogStory) {
<p>Here is an example of <strong>BlogStory</strong> resolver for field <strong>author</strong> that uses deferring:</p>
<pre><code class="php">&lt;?php
'resolve' =&gt; function($blogStory) {
MyUserBuffer::add($blogStory['authorId']);
return new GraphQL\Deferred(function () use ($blogStory) {
@ -334,14 +366,13 @@ when one batched query could be executed instead of 10 distinct queries.</p>
}
</code></pre>
<p>In this example we fill up buffer with 10 author ids first. Then <strong>graphql-php</strong> continues
<p>In this example, we fill up the buffer with 10 author ids first. Then <strong>graphql-php</strong> continues
resolving other non-deferred fields until there are none of them left.</p>
<p>After that it calls <code>Closures</code> wrapped by <code>GraphQL\Deferred</code> which in turn load all buffered
ids once (using SQL IN(?), Redis MGET or other similar tools) and return final field value.</p>
<p>After that, it calls closures wrapped by <code>GraphQL\Deferred</code> which in turn load all buffered
ids once (using SQL IN(?), Redis MGET or other similar tools) and returns final field value.</p>
<p>Originally this approach was advocated by Facebook in their <a href="https://github.com/facebook/dataloader">Dataloader</a>
project.</p>
<p>This solution enables very interesting optimizations at no cost. Consider following query:</p>
<pre><code>{
project. This solution enables very interesting optimizations at no cost. Consider the following query:</p>
<pre><code class="graphql">{
topStories(limit: 10) {
author {
email
@ -357,29 +388,50 @@ project.</p>
}
</code></pre>
<p>Even if <code>author</code> field is located on different levels of 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 naive implementation.</p>
<p>Even though <strong>author</strong> 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 a naive implementation.</p>
<h1 id="async-php">Async PHP</h1>
<p>Since: 0.9.0</p>
<p>If your project runs in environment that supports async operations
(like <code>HHVM</code>, <code>ReactPHP</code>, <code>Icicle.io</code>, <code>appserver.io</code> <code>PHP threads</code>, etc) you can leverage
the power of your platform to resolve fields asynchronously.</p>
<p>Since: 0.10.0 (version 0.9.0 had slightly different API which still works, but is deprecated)</p>
<p>If your project runs in an 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 some fields asynchronously.</p>
<p>The only requirement: your platform must support the concept of Promises compatible with
<a href="https://promisesaplus.com/">Promises A+</a> specification.</p>
<p>To enable async support - set adapter for promises:</p>
<pre><code>GraphQL\GraphQL::setPromiseAdapter($adapter);
<p>To start using this feature, switch facade method for query execution from
<strong>executeQuery</strong> to <strong>promiseToExecute</strong>:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Executor\ExecutionResult;
$promise = GraphQL::promiseToExecute(
$promiseAdapter,
$schema,
$queryString,
$rootValue = null,
$contextValue = null,
$variableValues = null,
$operationName = null,
$fieldResolver = null,
$validationRules = null
);
$promise-&gt;then(function(ExecutionResult $result) {
return $result-&gt;toArray();
});
</code></pre>
<p>Where <code>$adapter</code> is an instance of class implementing <code>GraphQL\Executor\Promise\PromiseAdapter</code> interface.</p>
<p>Then in your <code>resolve</code> functions you should return <code>Promises</code> of your platform instead of
<code>GraphQL\Deferred</code> instances.</p>
<p>Platforms supported out of the box:</p>
<p>Where <strong>$promiseAdapter</strong> is an instance of:</p>
<ul>
<li><a href="https://github.com/reactphp/react">ReactPHP</a> (requires <strong>react/promise</strong> as composer dependency):
<code>GraphQL\GraphQL::setPromiseAdapter(new GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter());</code></li>
<li>
<p>For <a href="https://github.com/reactphp/react">ReactPHP</a> (requires <strong>react/promise</strong> as composer dependency): <br>
<code>GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter</code></p>
</li>
<li>
<p>Other platforms: write your own class implementing interface: <br>
<a href="../reference/#graphqlexecutorpromisepromiseadapter"><code>GraphQL\Executor\Promise\PromiseAdapter</code></a>. </p>
</li>
</ul>
<p>To integrate other platform - implement <code>GraphQL\Executor\Promise\PromiseAdapter</code> interface. </p>
<p>Then your <strong>resolve</strong> functions should return promises of your platform instead of <code>GraphQL\Deferred</code>s.</p>
</div>
</div>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +96,7 @@
</li>
<li class="">
<a class="" href="../type-system/input-types/">Input Types</a>
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -101,6 +106,10 @@
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -122,10 +131,13 @@
<li class="toctree-l2"><a href="#errors-in-graphql">Errors in GraphQL</a></li>
<li class="toctree-l2"><a href="#default-error-formatting">Default Error formatting</a></li>
<li class="toctree-l2"><a href="#debugging-tools">Debugging tools</a></li>
<li class="toctree-l2"><a href="#custom-error-formatting">Custom Error Formatting</a></li>
<li class="toctree-l2"><a href="#custom-error-handling-and-formatting">Custom Error Handling and Formatting</a></li>
<li class="toctree-l2"><a href="#schema-errors">Schema Errors</a></li>
@ -136,7 +148,17 @@
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -172,116 +194,164 @@
<div class="section">
<h1 id="errors-in-graphql">Errors in GraphQL</h1>
<p>Query execution process never throws exceptions. Instead all errors that occur during query execution
are caught, collected and included in response. </p>
<p>There are 3 types of errors in GraphQL (Syntax, Validation and Execution errors):</p>
<p><strong>Syntax</strong> errors are returned in response when query has invalid syntax and could not be parsed.
Example output for invalid query <code>{hello</code> (missing bracket):</p>
<pre><code class="php">[
'errors' =&gt; [
[
'message' =&gt; &quot;Syntax Error GraphQL request (1:7) Expected Name, found &lt;EOF&gt;\n\n1: {hello\n ^\n&quot;,
'locations' =&gt; [
['line' =&gt; 1, 'column' =&gt; 7]
]
]
]
]
</code></pre>
<p><strong>Validation</strong> errors - returned in response when query has semantic errors.
Example output for invalid query <code>{unknownField}</code>:</p>
<pre><code class="php">[
'errors' =&gt; [
[
'message' =&gt; 'Cannot query field &quot;unknownField&quot; on type &quot;Query&quot;.',
'locations' =&gt; [
['line' =&gt; 1, 'column' =&gt; 2]
]
]
]
]
</code></pre>
<p><strong>Execution</strong> errors - included in response when some field resolver throws
(or returns unexpected value). Example output for query with exception thrown in
field resolver <code>{fieldWithException}</code>:</p>
<pre><code class="php">[
'data' =&gt; [
'fieldWithException' =&gt; null
<p>Query execution process never throws exceptions. Instead, all errors are caught and collected.
After execution, they are available in <strong>$errors</strong> prop of
<a href="../reference/#graphqlexecutorexecutionresult"><code>GraphQL\Executor\ExecutionResult</code></a>.</p>
<p>When the result is converted to a serializable array using its <strong>toArray()</strong> method, all errors are
converted to arrays as well using default error formatting (see below). </p>
<p>Alternatively, you can apply <a href="#custom-error-handling-and-formatting">custom error filtering and formatting</a>
for your specific requirements.</p>
<h1 id="default-error-formatting">Default Error formatting</h1>
<p>By default, each error entry is converted to an associative array with following structure:</p>
<pre><code class="php">&lt;?php
[
'message' =&gt; 'Error message',
'category' =&gt; 'graphql',
'locations' =&gt; [
['line' =&gt; 1, 'column' =&gt; 2]
],
'errors' =&gt; [
[
'message' =&gt; 'Exception message thrown in field resolver',
'locations' =&gt; [
['line' =&gt; 1, 'column' =&gt; 2]
],
'path': [
'fieldWithException'
]
]
'path' =&gt; [
'listField',
0,
'fieldWithException'
]
]
];
</code></pre>
<p>Entry at key <strong>locations</strong> 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
the path to field with the error in query.</p>
<p>Entry at key <strong>path</strong> exists only for errors caused by exceptions thrown in resolvers.
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). </p>
<p><strong>Internal errors</strong></p>
<p>As of version <strong>0.10.0</strong>, all exceptions thrown in resolvers are reported with generic message <strong>"Internal server error"</strong>.
This is done to avoid information leak in production environments (e.g. database connection errors, file access errors, etc).</p>
<p>Only exceptions implementing interface <a href="../reference/#graphqlerrorclientaware"><code>GraphQL\Error\ClientAware</code></a> and claiming themselves as <strong>safe</strong> will
be reported with a full error message.</p>
<p>For example:</p>
<pre><code class="php">&lt;?php
use GraphQL\Error\ClientAware;
class MySafeException extends \Exception implements ClientAware
{
public function isClientSafe()
{
return true;
}
public function getCategory()
{
return 'businessLogic';
}
}
</code></pre>
<p>When such exception is thrown it will be reported with a full error message:</p>
<pre><code class="php">&lt;?php
[
'message' =&gt; 'My reported error',
'category' =&gt; 'businessLogic',
'locations' =&gt; [
['line' =&gt; 10, 'column' =&gt; 2]
],
'path' =&gt; [
'path',
'to',
'fieldWithException'
]
];
</code></pre>
<p>To change default <strong>"Internal server error"</strong> message to something else, use: </p>
<pre><code>GraphQL\Error\FormattedError::setInternalErrorMessage(&quot;Unexpected error&quot;);
</code></pre>
<p>Obviously when <strong>Syntax</strong> or <strong>Validation</strong> error is detected - process is interrupted and query is not
executed. In such scenarios response only contains <strong>errors</strong>, but not <strong>data</strong>.</p>
<p>GraphQL is forgiving to <strong>Execution</strong> 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
replaced with <code>null</code> and error entry will be added to response.</p>
<p>If exception is thrown in non-null field - error bubbles up to first nullable field. This nullable field is<br />
replaced with <code>null</code> and error entry is added to response. If all fields up to the root are non-null -
<strong>data</strong> entry will be removed from response and only <strong>errors</strong> key will be presented.</p>
<h1 id="debugging-tools">Debugging tools</h1>
<p>Each error entry contains pointer to line and column in original query string which caused
the error:</p>
<pre><code class="php">'locations' =&gt; [
['line' =&gt; 1, 'column' =&gt; 2]
]
<p>During development or debugging use <code>$result-&gt;toArray(true)</code> to add <strong>debugMessage</strong> key to
each formatted error entry. If you also want to add exception trace - pass flags instead:</p>
<pre><code>use GraphQL\Error\Debug;
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
$result = GraphQL::executeQuery(/*args*/)-&gt;toArray($debug);
</code></pre>
<p>GraphQL clients like <strong>Relay</strong> or <strong>GraphiQL</strong> leverage this information to highlight
actual piece of query containing error. </p>
<p>In some cases (like deep fragment fields) locations will include several entries to track down the
path to field with error in query.</p>
<p><strong>Execution</strong> errors also contain <strong>path</strong> from the very root field to actual field value producing
an error (including indexes for array types and fieldNames for object types). So in complex situation
this path could look like this:</p>
<pre><code class="php">'path' =&gt; [
'lastStoryPosted',
'author',
'friends',
3
'fieldWithException'
]
<p>This will make each error entry to look like this:</p>
<pre><code class="php">&lt;?php
[
'debugMessage' =&gt; 'Actual exception message',
'message' =&gt; 'Internal server error',
'category' =&gt; 'internal',
'locations' =&gt; [
['line' =&gt; 10, 'column' =&gt; 2]
],
'path' =&gt; [
'listField',
0,
'fieldWithException'
],
'trace' =&gt; [
/* Formatted original exception trace */
]
];
</code></pre>
<h1 id="custom-error-formatting">Custom Error Formatting</h1>
<p>If you want to apply custom formatting to errors - use <strong>GraphQL::executeAndReturnResult()</strong> instead
of <strong>GraphQL::execute()</strong>.</p>
<p>It has exactly the same <a href="../executing-queries/">signature</a>, but instead of array it
returns <code>GraphQL\Executor\ExecutionResult</code> instance which holds errors in public <strong>$errors</strong>
property and data in <strong>$data</strong> property.</p>
<p>Each entry of <strong>$errors</strong> array contains instance of <code>GraphQL\Error\Error</code> which wraps original
exceptions thrown by resolvers. To access original exceptions use <code>$error-&gt;getPrevious()</code> method.
But note that previous exception is only available for <strong>Execution</strong> errors and will be <code>null</code>
for <strong>Syntax</strong> or <strong>Validation</strong> errors.</p>
<p>If you prefer first resolver exception to be re-thrown, use following flags:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Error\Debug;
$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::RETHROW_INTERNAL_EXCEPTIONS;
// Following will throw if there was an exception in resolver during execution:
$result = GraphQL::executeQuery(/*args*/)-&gt;toArray($debug);
</code></pre>
<h1 id="custom-error-handling-and-formatting">Custom Error Handling and Formatting</h1>
<p>It is possible to define custom <strong>formatter</strong> and <strong>handler</strong> for result errors.</p>
<p><strong>Formatter</strong> is responsible for converting instances of <a href="../reference/#graphqlerrorerror"><code>GraphQL\Error\Error</code></a>
to an array. <strong>Handler</strong> is useful for error filtering and logging. </p>
<p>For example, these are default formatter and handler:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
$myErrorFormatter = function(Error $error) {
return FormattedError::createFromException($error);
};
$myErrorHandler = function(array $errors, callable $formatter) {
return array_map($formatter, $errors);
};
$result = GraphQL::executeQuery(/* $args */)
-&gt;setErrorFormatter($myErrorFormatter)
-&gt;setErrorHandler($myErrorHandler)
-&gt;toArray();
</code></pre>
<p>Note that when you pass <a href="#debugging-tools">debug flags</a> to <strong>toArray()</strong> your custom formatter will still be
decorated with same debugging information mentioned above.</p>
<h1 id="schema-errors">Schema Errors</h1>
<p>So far we only covered errors which occur during query execution process. But schema definition can
also throw if there is an error in one of type definitions.</p>
also throw <code>GraphQL\Error\InvariantViolation</code> if there is an error in one of type definitions.</p>
<p>Usually such errors mean that there is some logical error in your schema and it is the only case
when it makes sense to return <code>500</code> error code for GraphQL endpoint:</p>
<pre><code class="php">try {
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Error\FormattedError;
try {
$schema = new Schema([
// ...
]);
$body = GraphQL::execute($schema, $query);
$body = GraphQL::executeQuery($schema, $query);
$status = 200;
} catch(\Exception $e) {
$body = json_encode([
'message' =&gt; 'Unexpected error'
]);
$body = [
'errors' =&gt; [FormattedError::createFromException($e)]
];
$status = 500;
}
@ -295,7 +365,7 @@ echo json_encode($body);
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../complementary-tools/" class="btn btn-neutral float-right" title="Complementary Tools">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../security/" class="btn btn-neutral float-right" title="Security">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../data-fetching/" class="btn btn-neutral" title="Fetching Data"><span class="icon icon-circle-arrow-left"></span> Previous</a>
@ -327,7 +397,7 @@ echo json_encode($body);
<span><a href="../data-fetching/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../complementary-tools/" style="color: #fcfcfc">Next &raquo;</a></span>
<span style="margin-left: 15px"><a href="../security/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +96,7 @@
</li>
<li class="">
<a class="" href="../type-system/input-types/">Input Types</a>
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -101,6 +106,10 @@
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -109,16 +118,21 @@
<a class="current" href="./">Executing Queries</a>
<ul class="subnav">
<li class="toctree-l2"><a href="#overview">Overview</a></li>
<li class="toctree-l2"><a href="#using-facade-method">Using Facade Method</a></li>
<li class="toctree-l2"><a href="#parsing">Parsing</a></li>
<li class="toctree-l2"><a href="#using-server">Using Server</a></li>
<ul>
<li><a class="toctree-l3" href="#server-configuration-options">Server configuration options</a></li>
<li><a class="toctree-l3" href="#query-batching">Query batching</a></li>
</ul>
<li class="toctree-l2"><a href="#validating">Validating</a></li>
<li class="toctree-l2"><a href="#executing">Executing</a></li>
<li class="toctree-l2"><a href="#custom-validation-rules">Custom Validation Rules</a></li>
</ul>
@ -136,7 +150,17 @@
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -171,27 +195,36 @@
<div role="main">
<div class="section">
<h1 id="overview">Overview</h1>
<h1 id="using-facade-method">Using Facade Method</h1>
<p>Query execution is a complex process involving multiple steps, including query <strong>parsing</strong>,
<strong>validating</strong> and finally <strong>executing</strong> against your <a href="../type-system/schema/">schema</a>.</p>
<p><strong>graphql-php</strong> provides convenient facade for this process in class <code>GraphQL\GraphQL</code>:</p>
<pre><code class="php">use GraphQL\GraphQL;
<p><strong>graphql-php</strong> provides a convenient facade for this process in class
<a href="../reference/#graphqlgraphql"><code>GraphQL\GraphQL</code></a>:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
$result = GraphQL::execute(
$result = GraphQL::executeQuery(
$schema,
$queryString,
$rootValue = null,
$contextValue = null,
$context = null,
$variableValues = null,
$operationName = null
$operationName = null,
$fieldResolver = null,
$validationRules = null
);
</code></pre>
<p>Method returns <code>array</code> with <strong>data</strong> and <strong>errors</strong> keys, as described by
<a href="http://facebook.github.io/graphql/#sec-Response-Format">GraphQL specs</a>.
This array is suitable for further serialization (e.g. using <code>json_encode</code>).
See also section on <a href="../error-handling/">error handling</a>.</p>
<p>Description of method arguments:</p>
<p>It returns an instance of <a href="../reference/#graphqlexecutorexecutionresult"><code>GraphQL\Executor\ExecutionResult</code></a>
which can be easily converted to array:</p>
<pre><code class="php">$serializableResult = $result-&gt;toArray();
</code></pre>
<p>Returned array contains <strong>data</strong> and <strong>errors</strong> keys, as described by the
<a href="http://facebook.github.io/graphql/#sec-Response-Format">GraphQL spec</a>.
This array is suitable for further serialization (e.g. using <strong>json_encode</strong>).
See also the section on <a href="../error-handling/">error handling and formatting</a>.</p>
<p>Description of <strong>executeQuery</strong> method arguments:</p>
<table>
<thead>
<tr>
@ -203,23 +236,23 @@ See also section on <a href="../error-handling/">error handling</a>.</p>
<tbody>
<tr>
<td>schema</td>
<td><code>GraphQL\Schema</code></td>
<td><a href="#"><code>GraphQL\Type\Schema</code></a></td>
<td><strong>Required.</strong> Instance of your application <a href="../type-system/schema/">Schema</a></td>
</tr>
<tr>
<td>queryString</td>
<td><code>string</code> or <code>GraphQL\Language\AST\DocumentNode</code></td>
<td><strong>Required.</strong> 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.</td>
<td><strong>Required.</strong> 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.</td>
</tr>
<tr>
<td>rootValue</td>
<td><code>mixed</code></td>
<td>Any value that represents a root of your data graph. It is passed as 1st argument to field resolvers of <a href="../type-system/schema/#query-and-mutation-types">Query type</a>. Can be omitted or set to null if actual root values are fetched by Query type itself.</td>
<td>Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of <a href="../type-system/schema/#query-and-mutation-types">Query type</a>. Can be omitted or set to null if actual root values are fetched by Query type itself.</td>
</tr>
<tr>
<td>contextValue</td>
<td>context</td>
<td><code>mixed</code></td>
<td>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 <a href="../type-system/object-types/#field-configuration-options">Field Definitions</a> for reference) <strong>graphql-php</strong> never modifies this value and passes it <em>as is</em> to all underlying resolvers.</td>
<td>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 <a href="../type-system/object-types/#field-configuration-options">Field Definitions</a> for reference) <strong>graphql-php</strong> never modifies this value and passes it <em>as is</em> to all underlying resolvers.</td>
</tr>
<tr>
<td>variableValues</td>
@ -231,17 +264,214 @@ See also section on <a href="../error-handling/">error handling</a>.</p>
<td><code>string</code></td>
<td>Allows the caller to specify which operation in queryString will be run, in cases where queryString contains multiple top-level operations.</td>
</tr>
<tr>
<td>fieldResolver</td>
<td><code>callable</code></td>
<td>A resolver function to use when one is not provided by the schema. If not provided, the <a href="../data-fetching/#default-field-resolver">default field resolver is used</a>.</td>
</tr>
<tr>
<td>validationRules</td>
<td><code>array</code></td>
<td>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)</td>
</tr>
</tbody>
</table>
<h1 id="parsing">Parsing</h1>
<p>Following reading describes implementation details of query execution process. It may clarify some
internals of GraphQL but is not required in order to use it. Feel free to skip to next section
on <a href="../error-handling/">Error Handling</a> for essentials.</p>
<p>TODOC</p>
<h1 id="validating">Validating</h1>
<p>TODOC</p>
<h1 id="executing">Executing</h1>
<p>TODOC</p>
<h1 id="using-server">Using Server</h1>
<p>If you are building HTTP GraphQL API, you may prefer our Standard Server
(compatible with <a href="https://github.com/graphql/express-graphql">express-graphql</a>).
It supports more features out of the box, including parsing HTTP requests, producing a spec-compliant response; <a href="#query-batching">batched queries</a>; persisted queries.</p>
<p>Usage example (with plain PHP):</p>
<pre><code class="php">&lt;?php
use GraphQL\Server\StandardServer;
$server = new StandardServer([/* server options, see below */]);
$server-&gt;handleRequest(); // parses PHP globals and emits response
</code></pre>
<p>Server also supports <a href="http://www.php-fig.org/psr/psr-7/">PSR-7 request/response interfaces</a>:</p>
<pre><code class="php">&lt;?php
use GraphQL\Server\StandardServer;
use GraphQL\Executor\ExecutionResult;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
/** @var ServerRequestInterface $psrRequest */
/** @var ResponseInterface $psrResponse */
/** @var StreamInterface $psrBodyStream */
$server = new StandardServer([/* server options, see below */]);
$psrResponse = $server-&gt;processPsrRequest($psrRequest, $psrResponse, $psrBodyStream);
// Alternatively create PSR-7 response yourself:
/** @var ExecutionResult|ExecutionResult[] $result */
$result = $server-&gt;executePsrRequest($psrRequest);
$psrResponse = new SomePsr7ResponseImplementation(json_encode($result));
</code></pre>
<p>PSR-7 is useful when you want to integrate the server into existing framework:</p>
<ul>
<li><a href="https://laravel.com/docs/5.1/requests#psr7-requests">PSR-7 for Laravel</a></li>
<li><a href="https://symfony.com/doc/current/request/psr7.html">Symfony PSR-7 Bridge</a></li>
<li><a href="https://www.slimframework.com/docs/concepts/value-objects.html">Slim</a></li>
<li><a href="http://zendframework.github.io/zend-expressive/">Zend Expressive</a></li>
</ul>
<h2 id="server-configuration-options">Server configuration options</h2>
<table>
<thead>
<tr>
<th>Argument</th>
<th>Type</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>schema</td>
<td><a href="../reference/#graphqltypeschema"><code>Schema</code></a></td>
<td><strong>Required.</strong> Instance of your application <a href="../type-system/schema/">Schema</a></td>
</tr>
<tr>
<td>rootValue</td>
<td><code>mixed</code></td>
<td>Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of <a href="../type-system/schema/#query-and-mutation-types">Query type</a>. Can be omitted or set to null if actual root values are fetched by Query type itself.</td>
</tr>
<tr>
<td>context</td>
<td><code>mixed</code></td>
<td>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 <a href="../type-system/object-types/#field-configuration-options">Field Definitions</a> for reference) <strong>graphql-php</strong> never modifies this value and passes it <em>as is</em> to all underlying resolvers.</td>
</tr>
<tr>
<td>fieldResolver</td>
<td><code>callable</code></td>
<td>A resolver function to use when one is not provided by the schema. If not provided, the <a href="../data-fetching/#default-field-resolver">default field resolver is used</a>.</td>
</tr>
<tr>
<td>validationRules</td>
<td><code>array</code> or <code>callable</code></td>
<td>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 <code>callable</code> 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> <strong>function (<a href="../reference/#graphqlserveroperationparams">OperationParams</a> $params, DocumentNode $node, $operationType): array</strong></td>
</tr>
<tr>
<td>queryBatching</td>
<td><code>bool</code></td>
<td>Flag indicating whether this server supports query batching (<a href="https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862">apollo-style</a>).<br><br> Defaults to <strong>false</strong></td>
</tr>
<tr>
<td>debug</td>
<td><code>int</code></td>
<td>Debug flags. See <a href="../error-handling/#debugging-tools">docs on error debugging</a> (flag values are the same).</td>
</tr>
<tr>
<td>persistentQueryLoader</td>
<td><code>callable</code></td>
<td>A function which is called to fetch actual query when server encounters <strong>queryId</strong> in request vs <strong>query</strong>.<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> <strong>function ($queryId, <a href="../reference/#graphqlserveroperationparams">OperationParams</a> $params)</strong> <br><br>Function is expected to return query <strong>string</strong> or parsed <strong>DocumentNode</strong> <br><br> <a href="https://dev-blog.apollodata.com/persisted-graphql-queries-with-apollo-client-119fd7e6bba5">Read more about persisted queries</a>.</td>
</tr>
<tr>
<td>errorFormatter</td>
<td><code>callable</code></td>
<td>Custom error formatter. See <a href="../error-handling/#custom-error-handling-and-formatting">error handling docs</a>.</td>
</tr>
<tr>
<td>errorsHandler</td>
<td><code>callable</code></td>
<td>Custom errors handler. See <a href="../error-handling/#custom-error-handling-and-formatting">error handling docs</a>.</td>
</tr>
<tr>
<td>promiseAdapter</td>
<td><a href="../reference/#graphqlexecutorpromisepromiseadapter"><code>PromiseAdapter</code></a></td>
<td>Required for <a href="../data-fetching/#async-php">Async PHP</a> only.</td>
</tr>
</tbody>
</table>
<p><strong>Server config instance</strong></p>
<p>If you prefer fluid interface for config with autocomplete in IDE and static time validation,
use <a href="../reference/#graphqlserverserverconfig"><code>GraphQL\Server\ServerConfig</code></a> instead of an array:</p>
<pre><code class="php">&lt;?php
use GraphQL\Server\ServerConfig;
use GraphQL\Server\StandardServer;
$config = ServerConfig::create()
-&gt;setSchema($schema)
-&gt;setErrorFormatter($myFormatter)
-&gt;setDebug($debug)
;
$server = new StandardServer($config);
</code></pre>
<h2 id="query-batching">Query batching</h2>
<p>Standard Server supports query batching (<a href="https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862">apollo-style</a>).</p>
<p>One of the major benefits of Server over a sequence of <strong>executeQuery()</strong> calls is that
<a href="../data-fetching/#solving-n1-problem">Deferred resolvers</a> won't be isolated in queries.
So for example following batch will require single DB request (if user field is deferred):</p>
<pre><code class="json">[
{
&quot;query&quot;: &quot;{user(id: 1)} { id }&quot;
},
{
&quot;query&quot;: &quot;{user(id: 2)} { id }&quot;
},
{
&quot;query&quot;: &quot;{user(id: 3)} { id }&quot;
}
]
</code></pre>
<p>To enable query batching, pass <strong>queryBatching</strong> option in server config:</p>
<pre><code class="php">&lt;?php
use GraphQL\Server\StandardServer;
$server = new StandardServer([
'queryBatching' =&gt; true
]);
</code></pre>
<h1 id="custom-validation-rules">Custom Validation Rules</h1>
<p>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.</p>
<p>Add rules globally:</p>
<pre><code class="php">&lt;?php
use GraphQL\Validator\Rules;
use GraphQL\Validator\DocumentValidator;
// Add to standard set of rules globally:
DocumentValidator::addRule(new Rules\DisableIntrospection());
</code></pre>
<p>Custom rules per execution:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Validator\Rules;
$myValiationRules = array_merge(
GraphQL::getStandardValidationRules(),
[
new Rules\QueryComplexity(100),
new Rules\DisableIntrospection()
]
);
$result = GraphQL::executeQuery(
$schema,
$queryString,
$rootValue = null,
$context = null,
$variableValues = null,
$operationName = null,
$fieldResolver = null,
$myValiationRules // &lt;-- this will override global validation rules for this request
);
</code></pre>
<p>Or with a standard server:</p>
<pre><code class="php">&lt;?php
use GraphQL\Server\StandardServer;
$server = new StandardServer([
'validationRules' =&gt; $myValiationRules
]);
</code></pre>
</div>
</div>
@ -252,7 +482,7 @@ on <a href="../error-handling/">Error Handling</a> for essentials.</p>
<a href="../data-fetching/" class="btn btn-neutral float-right" title="Fetching Data">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../type-system/schema/" class="btn btn-neutral" title="Schema"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../type-system/type-language/" class="btn btn-neutral" title="Using Type Language"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
@ -278,7 +508,7 @@ on <a href="../error-handling/">Error Handling</a> for essentials.</p>
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../type-system/schema/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span><a href="../type-system/type-language/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../data-fetching/" style="color: #fcfcfc">Next &raquo;</a></span>

View File

@ -80,7 +80,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -112,7 +117,7 @@
</li>
<li class="">
<a class="" href="../type-system/input-types/">Input Types</a>
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -122,6 +127,10 @@
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -142,7 +151,17 @@
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -179,7 +198,7 @@
<h1 id="prerequisites">Prerequisites</h1>
<p>This documentation assumes your familiarity with GraphQL concepts. If it is not the case -
first learn about GraphQL on <a href="http://graphql.org/learn/">official website</a>.</p>
first learn about GraphQL on <a href="http://graphql.org/learn/">the official website</a>.</p>
<h1 id="installation">Installation</h1>
<p>Using <a href="https://getcomposer.org/doc/00-intro.md">composer</a>, simply run:</p>
<pre><code class="sh">composer require webonyx/graphql-php
@ -191,7 +210,7 @@ they are explained in <a href="https://github.com/webonyx/graphql-php/blob/maste
<h1 id="install-tools-optional">Install Tools (optional)</h1>
<p>While it is possible to communicate with GraphQL API using regular HTTP tools it is way
more convenient for humans to use <a href="https://github.com/graphql/graphiql">GraphiQL</a> - an in-browser
ide for exploring GraphQL APIs.</p>
IDE for exploring GraphQL APIs.</p>
<p>It provides syntax-highlighting, auto-completion and auto-generated documentation for
GraphQL API.</p>
<p>The easiest way to use it is to install one of the existing Google Chrome extensions:</p>
@ -199,10 +218,10 @@ GraphQL API.</p>
<li><a href="https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij">ChromeiQL</a></li>
<li><a href="https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp">GraphiQL Feen</a></li>
</ul>
<p>Alternatively you can follow instructions on <a href="https://github.com/graphql/graphiql">GraphiQL</a>
<p>Alternatively, you can follow instructions on <a href="https://github.com/graphql/graphiql">the GraphiQL</a>
page and install it locally.</p>
<h1 id="hello-world">Hello World</h1>
<p>Let's create type system that will be capable to process following simple query:</p>
<p>Let's create a type system that will be capable to process following simple query:</p>
<pre><code>query {
echo(message: &quot;Hello World&quot;)
}
@ -227,18 +246,19 @@ $queryType = new ObjectType([
],
],
]);
</code></pre>
<p>(Note: type definition can be expressed in <a href="../type-system/#type-definition-styles">different styles</a>,
but this example uses <strong>inline</strong> style for simplicity)</p>
<p>The interesting piece here is <code>resolve</code> option of field definition. It is responsible for retuning
value of our field. Values of <strong>scalar</strong> fields will be directly included in response while values of
<strong>complex</strong> fields (objects, interfaces, unions) will be passed down to nested field resolvers
<p>The interesting piece here is <strong>resolve</strong> option of field definition. It is responsible for returning
a value of our field. Values of <strong>scalar</strong> fields will be directly included in response while values of
<strong>composite</strong> fields (objects, interfaces, unions) will be passed down to nested field resolvers
(not in this example though).</p>
<p>Now when our type is ready, let's create GraphQL endpoint for it <code>graphql.php</code>:</p>
<p>Now when our type is ready, let's create GraphQL endpoint file for it <strong>graphql.php</strong>:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Schema;
use GraphQL\Type\Schema;
$schema = new Schema([
'query' =&gt; $queryType
@ -251,29 +271,33 @@ $variableValues = isset($input['variables']) ? $input['variables'] : null;
try {
$rootValue = ['prefix' =&gt; 'You said: '];
$result = GraphQL::execute($schema, $query, $rootValue, null, $variableValues);
$result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues);
$output = $result-&gt;toArray();
} catch (\Exception $e) {
$result = [
'error' =&gt; [
'message' =&gt; $e-&gt;getMessage()
$output = [
'errors' =&gt; [
[
'message' =&gt; $e-&gt;getMessage()
]
]
];
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($result);
header('Content-Type: application/json');
echo json_encode($output);
</code></pre>
<p>Our example is ready. Try it by running:</p>
<p>Our example is finished. Try it by running:</p>
<pre><code class="sh">php -S localhost:8000 graphql.php
curl http://localhost:8000 -d '{&quot;query&quot;: &quot;query { echo(message: \&quot;Hello World\&quot;) }&quot; }'
curl http://localhost:8080 -d '{&quot;query&quot;: &quot;query { echo(message: \&quot;Hello World\&quot;) }&quot; }'
</code></pre>
<p>Check out the full <a href="https://github.com/webonyx/graphql-php/blob/master/examples/00-hello-world">source code</a> of this example.</p>
<p>Check out the full <a href="https://github.com/webonyx/graphql-php/blob/master/examples/00-hello-world">source code</a> of this example
which also includes simple mutation.</p>
<p>Obviously hello world only scratches the surface of what is possible.
So check out next example, which is closer to real-world apps.
Or keep reading about <a href="../type-system/">schema definition</a>.</p>
<h1 id="blog-example">Blog example</h1>
<p>It is often easier to start with full-featured example and then get back to documentation
<p>It is often easier to start with a full-featured example and then get back to documentation
for your own work. </p>
<p>Check out <a href="https://github.com/webonyx/graphql-php/tree/master/examples/01-blog">Blog example of GraphQL API</a>.
It is quite close to real-world GraphQL hierarchies. Follow instructions and try it yourself in ~10 minutes.</p>
@ -284,7 +308,7 @@ It is quite close to real-world GraphQL hierarchies. Follow instructions and try
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../type-system/" class="btn btn-neutral float-right" title="Introduction">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../complementary-tools/" class="btn btn-neutral float-right" title="Complementary Tools">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href=".." class="btn btn-neutral" title="About"><span class="icon icon-circle-arrow-left"></span> Previous</a>
@ -316,7 +340,7 @@ It is quite close to real-world GraphQL hierarchies. Follow instructions and try
<span><a href=".." style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../type-system/" style="color: #fcfcfc">Next &raquo;</a></span>
<span style="margin-left: 15px"><a href="../complementary-tools/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>

269
how-it-works/index.html Executable file
View File

@ -0,0 +1,269 @@
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="../img/favicon.ico">
<title>How it works - graphql-php</title>
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
<link rel="stylesheet" href="../css/highlight.css">
<script>
// Current page data
var mkdocs_page_name = "How it works";
var mkdocs_page_input_path = "how-it-works.md";
var mkdocs_page_url = "/how-it-works/";
</script>
<script src="../js/jquery-2.1.1.min.js"></script>
<script src="../js/modernizr-2.8.3.min.js"></script>
<script type="text/javascript" src="../js/highlight.pack.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> graphql-php</a>
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<ul class="current">
<li class="toctree-l1">
<a class="" href="..">About</a>
</li>
<li class="toctree-l1">
<a class="" href="../getting-started/">Getting Started</a>
</li>
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
<a class="" href="../type-system/">Introduction</a>
</li>
<li class="">
<a class="" href="../type-system/object-types/">Object Types</a>
</li>
<li class="">
<a class="" href="../type-system/scalar-types/">Scalar Types</a>
</li>
<li class="">
<a class="" href="../type-system/enum-types/">Enumeration Types</a>
</li>
<li class="">
<a class="" href="../type-system/lists-and-nonnulls/">Lists and Non-Null</a>
</li>
<li class="">
<a class="" href="../type-system/interfaces/">Interfaces</a>
</li>
<li class="">
<a class="" href="../type-system/unions/">Unions</a>
</li>
<li class="">
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
<a class="" href="../type-system/directives/">Directives</a>
</li>
<li class="">
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
<li class="toctree-l1">
<a class="" href="../executing-queries/">Executing Queries</a>
</li>
<li class="toctree-l1">
<a class="" href="../data-fetching/">Fetching Data</a>
</li>
<li class="toctree-l1">
<a class="" href="../error-handling/">Handling Errors</a>
</li>
<li class="toctree-l1">
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1 current">
<a class="current" href="./">How it works</a>
<ul class="subnav">
<li class="toctree-l2"><a href="#overview">Overview</a></li>
<li class="toctree-l2"><a href="#parsing">Parsing</a></li>
<li class="toctree-l2"><a href="#validating">Validating</a></li>
<li class="toctree-l2"><a href="#executing">Executing</a></li>
<li class="toctree-l2"><a href="#errors-explained">Errors explained</a></li>
</ul>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
</div>
&nbsp;
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">graphql-php</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="..">Docs</a> &raquo;</li>
<li>How it works</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main">
<div class="section">
<h1 id="overview">Overview</h1>
<p>Following reading describes implementation details of query execution process. It may clarify some
internals of GraphQL runtime but is not required to use it.</p>
<h1 id="parsing">Parsing</h1>
<p>TODOC</p>
<h1 id="validating">Validating</h1>
<p>TODOC</p>
<h1 id="executing">Executing</h1>
<p>TODOC</p>
<h1 id="errors-explained">Errors explained</h1>
<p>There are 3 types of errors in GraphQL:</p>
<ul>
<li><strong>Syntax</strong>: query has invalid syntax and could not be parsed;</li>
<li><strong>Validation</strong>: query is incompatible with type system (e.g. unknown field is requested);</li>
<li><strong>Execution</strong>: occurs when some field resolver throws (or returns unexpected value).</li>
</ul>
<p>Obviously, when <strong>Syntax</strong> or <strong>Validation</strong> error is detected - the process is interrupted and
the query is not executed.</p>
<p>Execution process never throws exceptions. Instead, all errors are caught and collected in
execution result.</p>
<p>GraphQL is forgiving to <strong>Execution</strong> 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
replaced with <strong>null</strong> and error entry will be registered.</p>
<p>If an exception is thrown in the non-null field - error bubbles up to the first nullable field.
This nullable field is replaced with <strong>null</strong> and error entry is added to the result.
If all fields up to the root are non-null - <strong>data</strong> entry will be removed from the result<br />
and only <strong>errors</strong> key will be presented.</p>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../reference/" class="btn btn-neutral float-right" title="Class Reference">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../security/" class="btn btn-neutral" title="Security"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" style="cursor: pointer">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../security/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../reference/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../js/theme.js"></script>
</body>
</html>

View File

@ -76,7 +76,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -108,7 +113,7 @@
</li>
<li class="">
<a class="" href="type-system/input-types/">Input Types</a>
<a class="" href="type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -118,6 +123,10 @@
<a class="" href="type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -138,7 +147,17 @@
<li class="toctree-l1">
<a class="" href="complementary-tools/">Complementary Tools</a>
<a class="" href="security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="reference/">Class Reference</a>
</li>
</ul>
@ -179,35 +198,39 @@
<a href="https://packagist.org/packages/webonyx/graphql-php"><img alt="Latest Stable Version" src="https://poser.pugx.org/webonyx/graphql-php/version" /></a>
<a href="https://packagist.org/packages/webonyx/graphql-php"><img alt="License" src="https://poser.pugx.org/webonyx/graphql-php/license" /></a></p>
<h1 id="about-graphql">About GraphQL</h1>
<p>GraphQL is a modern way to build HTTP APIs consumed by web and mobile clients.
<p>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 <strong>existing applications</strong>).</p>
<p>GraphQL itself is a <a href="https://github.com/facebook/graphql">specification</a> designed by Facebook
engineers. Various implementations of this specification were written
<a href="http://graphql.org/code/">for different languages and environments</a>.</p>
<p>Great overview of GraphQL features and benefits is presented on <a href="http://graphql.org/">official website</a>.
<a href="http://graphql.org/code/">in different languages and environments</a>.</p>
<p>Great overview of GraphQL features and benefits is presented on <a href="http://graphql.org/">the official website</a>.
All of them equally apply to this PHP implementation. </p>
<h1 id="about-graphql-php">About graphql-php</h1>
<p><strong>graphql-php</strong> is a feature-complete implementation of GraphQL specification in PHP (5.4+, 7.0+).
<p><strong>graphql-php</strong> is a feature-complete implementation of GraphQL specification in PHP (5.5+, 7.0+).
It was originally inspired by <a href="https://github.com/graphql/graphql-js">reference JavaScript implementation</a>
published by Facebook.</p>
<p>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
are used. Instead it provides tools for creating rich API for your existing app. </p>
<p>These tools include:</p>
are used. Instead, it provides tools for creating rich API for your existing app.</p>
<p>Library features include:</p>
<ul>
<li>Primitives to express your app as a Type System</li>
<li>Tools for validation and introspection of this Type System (for compatibility with tools like <a href="./complementary-tools/#tools">GraphiQL</a>)</li>
<li>Tools for parsing, validating and executing GraphQL queries against this Type System</li>
<li>Rich error reporting, including query validation and execution errors</li>
<li>Optional tools for parsing GraphQL Schema Definition language</li>
<li>Primitives to express your app as a <a href="type-system/">Type System</a></li>
<li>Validation and introspection of this Type System (for compatibility with tools like <a href="complementary-tools/#tools">GraphiQL</a>)</li>
<li>Parsing, validating and <a href="executing-queries/">executing GraphQL queries</a> against this Type System</li>
<li>Rich <a href="error-handling/">error reporting</a>, including query validation and execution errors</li>
<li>Optional tools for <a href="type-system/type-language/">parsing GraphQL Type language</a></li>
<li>Tools for <a href="./data-fetching.md/#solving-n1-problem">batching requests</a> to backend storage</li>
<li><a href="./data-fetching.md/#async-php">Async PHP platforms support</a> via promises</li>
<li><a href="./executing-queries.md/#using-server">Standard HTTP server</a></li>
</ul>
<p>Also several <a href="./complementary-tools/">complementary tools</a> are available which provide integrations with
<p>Also, several <a href="complementary-tools/">complementary tools</a> are available which provide integrations with
existing PHP frameworks, add support for Relay, etc.</p>
<h2 id="current-status">Current Status</h2>
<p>First version of this library (v0.1) was released on August 10th 2015.</p>
<p>Current version (v0.9) supports all features described by GraphQL specification
<p>The first version of this library (v0.1) was released on August 10th 2015.</p>
<p>The current version (v0.10) supports all features described by GraphQL specification
(including April 2016 add-ons) as well as some experimental features like
Schema Language parser.</p>
<a href="type-system/type-language/">Schema Language parser</a> and
<a href="reference/#graphqlutilsschemaprinter">Schema printer</a>.</p>
<p>Ready for real-world usage. </p>
<h2 id="github">Github</h2>
<p>Project source code is <a href="https://github.com/webonyx/graphql-php">hosted on GitHub</a>.</p>
@ -257,5 +280,5 @@ Schema Language parser.</p>
<!--
MkDocs version : 0.16.3
Build Date UTC : 2017-04-25 11:15:39
Build Date UTC : 2017-08-20 16:28:58
-->

File diff suppressed because one or more lines are too long

2237
reference/index.html Executable file

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -87,7 +92,7 @@
</li>
<li class="">
<a class="" href="type-system/input-types/">Input Types</a>
<a class="" href="type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -97,6 +102,10 @@
<a class="" href="type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -117,7 +126,17 @@
<li class="toctree-l1">
<a class="" href="complementary-tools/">Complementary Tools</a>
<a class="" href="security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="reference/">Class Reference</a>
</li>
</ul>

314
security/index.html Executable file
View File

@ -0,0 +1,314 @@
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="../img/favicon.ico">
<title>Security - graphql-php</title>
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../css/theme.css" type="text/css" />
<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
<link rel="stylesheet" href="../css/highlight.css">
<script>
// Current page data
var mkdocs_page_name = "Security";
var mkdocs_page_input_path = "security.md";
var mkdocs_page_url = "/security/";
</script>
<script src="../js/jquery-2.1.1.min.js"></script>
<script src="../js/modernizr-2.8.3.min.js"></script>
<script type="text/javascript" src="../js/highlight.pack.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-nav-search">
<a href=".." class="icon icon-home"> graphql-php</a>
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<ul class="current">
<li class="toctree-l1">
<a class="" href="..">About</a>
</li>
<li class="toctree-l1">
<a class="" href="../getting-started/">Getting Started</a>
</li>
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
<a class="" href="../type-system/">Introduction</a>
</li>
<li class="">
<a class="" href="../type-system/object-types/">Object Types</a>
</li>
<li class="">
<a class="" href="../type-system/scalar-types/">Scalar Types</a>
</li>
<li class="">
<a class="" href="../type-system/enum-types/">Enumeration Types</a>
</li>
<li class="">
<a class="" href="../type-system/lists-and-nonnulls/">Lists and Non-Null</a>
</li>
<li class="">
<a class="" href="../type-system/interfaces/">Interfaces</a>
</li>
<li class="">
<a class="" href="../type-system/unions/">Unions</a>
</li>
<li class="">
<a class="" href="../type-system/input-types/">Mutations and Input Types</a>
</li>
<li class="">
<a class="" href="../type-system/directives/">Directives</a>
</li>
<li class="">
<a class="" href="../type-system/schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-system/type-language/">Using Type Language</a>
</li>
</ul>
</li>
<li class="toctree-l1">
<a class="" href="../executing-queries/">Executing Queries</a>
</li>
<li class="toctree-l1">
<a class="" href="../data-fetching/">Fetching Data</a>
</li>
<li class="toctree-l1">
<a class="" href="../error-handling/">Handling Errors</a>
</li>
<li class="toctree-l1 current">
<a class="current" href="./">Security</a>
<ul class="subnav">
<li class="toctree-l2"><a href="#query-complexity-analysis">Query Complexity Analysis</a></li>
<li class="toctree-l2"><a href="#limiting-query-depth">Limiting Query Depth</a></li>
<li class="toctree-l2"><a href="#disabling-introspection">Disabling Introspection</a></li>
</ul>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
</div>
&nbsp;
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="..">graphql-php</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="..">Docs</a> &raquo;</li>
<li>Security</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main">
<div class="section">
<h1 id="query-complexity-analysis">Query Complexity Analysis</h1>
<p>This is a PHP port of <a href="http://sangria-graphql.org/learn/#query-complexity-analysis">Query Complexity Analysis</a> in Sangria implementation.</p>
<p>Complexity analysis is a separate validation rule which calculates query complexity score before execution.
Every field in the query gets a default score 1 (including ObjectType nodes). Total complexity of the
query is the sum of all field scores. For example, the complexity of introspection query is <strong>109</strong>.</p>
<p>If this score exceeds a threshold, a query is not executed and an error is returned instead.</p>
<p>Complexity analysis is disabled by default. To enabled it, add validation rule:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Validator\Rules\QueryComplexity;
use GraphQL\Validator\DocumentValidator;
$rule = new QueryComplexity($maxQueryComplexity = 100);
DocumentValidator::addRule($rule);
GraphQL::executeQuery(/*...*/);
</code></pre>
<p>This will set the rule globally. Alternatively, you can provide validation rules <a href="../executing-queries/#custom-validation-rules">per execution</a>.</p>
<p>To customize field score add <strong>complexity</strong> function to field definition:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$type = new ObjectType([
'name' =&gt; 'MyType',
'fields' =&gt; [
'someList' =&gt; [
'type' =&gt; Type::listOf(Type::string()),
'args' =&gt; [
'limit' =&gt; [
'type' =&gt; Type::int(),
'defaultValue' =&gt; 10
]
],
'complexity' =&gt; function($childrenComplexity, $args) {
return $childrenComplexity * $args['limit'];
}
]
]
]);
</code></pre>
<h1 id="limiting-query-depth">Limiting Query Depth</h1>
<p>This is a PHP port of <a href="http://sangria-graphql.org/learn/#limiting-query-depth">Limiting Query Depth</a> in Sangria implementation.
For example, max depth of the introspection query is <strong>7</strong>.</p>
<p>It is disabled by default. To enable it, add following validation rule:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Validator\Rules\QueryDepth;
use GraphQL\Validator\DocumentValidator;
$rule = new QueryDepth($maxDepth = 10);
DocumentValidator::addRule($rule);
GraphQL::executeQuery(/*...*/);
</code></pre>
<p>This will set the rule globally. Alternatively, you can provide validation rules <a href="../executing-queries/#custom-validation-rules">per execution</a>.</p>
<h1 id="disabling-introspection">Disabling Introspection</h1>
<p><a href="http://graphql.org/learn/introspection/">Introspection</a> is a mechanism for fetching schema structure.
It is used by tools like GraphiQL for auto-completion, query validation, etc.</p>
<p>Introspection is enabled by default. It means that anybody can get a full description of your schema by
sending a special query containing meta fields <strong>__type</strong> and <strong>__schema</strong> .</p>
<p>If you are not planning to expose your API to the general public, it makes sense to disable this feature.</p>
<p>GraphQL PHP provides you separate validation rule which prohibits queries that contain
<strong>__type</strong> or <strong>__schema</strong> fields. To disable introspection, add following rule:</p>
<pre><code class="php">&lt;?php
use GraphQL\GraphQL;
use GraphQL\Validator\Rules\DisableIntrospection;
use GraphQL\Validator\DocumentValidator;
DocumentValidator::addRule(new DisableIntrospection());
GraphQL::executeQuery(/*...*/);
</code></pre>
<p>This will set the rule globally. Alternatively, you can provide validation rules <a href="../executing-queries/#custom-validation-rules">per execution</a>.</p>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../how-it-works/" class="btn btn-neutral float-right" title="How it works">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../error-handling/" class="btn btn-neutral" title="Handling Errors"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" style="cursor: pointer">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../error-handling/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../how-it-works/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../js/theme.js"></script>
</body>
</html>

View File

@ -4,7 +4,7 @@
<url>
<loc>/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
@ -12,7 +12,15 @@
<url>
<loc>/getting-started/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/complementary-tools/</loc>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
@ -21,61 +29,67 @@
<url>
<loc>/type-system/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/object-types/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/scalar-types/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/enum-types/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/lists-and-nonnulls/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/interfaces/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/unions/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/input-types/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/directives/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/schema/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/type-system/type-language/</loc>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
@ -84,7 +98,7 @@
<url>
<loc>/executing-queries/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
@ -92,7 +106,7 @@
<url>
<loc>/data-fetching/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
@ -100,15 +114,31 @@
<url>
<loc>/error-handling/</loc>
<lastmod>2017-04-25</lastmod>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/complementary-tools/</loc>
<lastmod>2017-04-25</lastmod>
<loc>/security/</loc>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/how-it-works/</loc>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>/reference/</loc>
<lastmod>2017-08-20</lastmod>
<changefreq>daily</changefreq>
</url>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +96,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class=" current">
@ -110,6 +115,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -130,7 +139,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -155,7 +174,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -170,13 +189,13 @@
<div class="section">
<h1 id="built-in-directives">Built-in directives</h1>
<p>Directive is a way for 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
<p>The directive is a way for a client to give GraphQL server additional context and hints on how to execute
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.</p>
<p>GraphQL specification includes two built-in directives:</p>
<ul>
<li><code>@include(if: Boolean)</code> Only include this field or fragment in the result if the argument is <code>true</code> </li>
<li><code>@skip(if: Boolean)</code> Skip this field or fragment if the argument is <code>true</code></li>
<li><strong>@include(if: Boolean)</strong> Only include this field or fragment in the result if the argument is <strong>true</strong> </li>
<li><strong>@skip(if: Boolean)</strong> Skip this field or fragment if the argument is <strong>true</strong></li>
</ul>
<p>For example:</p>
<pre><code class="graphql">query Hero($episode: Episode, $withFriends: Boolean!) {
@ -189,46 +208,41 @@ query in any way the server desires.</p>
}
</code></pre>
<p>Here if <code>$withFriends</code> variable is set to <code>false</code> - friends section will be ignored and excluded
from response. Important implementation detail: those fields will never be executed
<p>Here if <strong>$withFriends</strong> variable is set to <strong>false</strong> - friends section will be ignored and excluded
from the response. Important implementation detail: those fields will never be executed
(not just removed from response after execution).</p>
<h1 id="custom-directives">Custom directives</h1>
<p><strong>graphql-php</strong> supports custom directives even though their presence does not affect execution of fields.
But you can use <code>GraphQL\Type\Definition\ResolveInfo</code> in field resolvers to modify the output depending
on those directives or perform statistics collection.</p>
<p><strong>graphql-php</strong> supports custom directives even though their presence does not affect the execution of fields.
But you can use <a href="../../reference/#graphqltypedefinitionresolveinfo"><code>GraphQL\Type\Definition\ResolveInfo</code></a>
in field resolvers to modify the output depending on those directives or perform statistics collection.</p>
<p>Other use case is your own query validation rules relying on custom directives.</p>
<p>In <strong>graphql-php</strong> custom directive is an instance of <code>GraphQL\Type\Definition\Directive</code>
(or one of it subclasses) which accepts an array with following options:</p>
<pre><code class="php">use GraphQL\Type\Definition\Directive;
(or one of its subclasses) which accepts an array of following options:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\DirectiveLocation;
use GraphQL\Type\Definition\FieldArgument;
$trackDirective = new Directive([
'name' =&gt; 'track',
'description' =&gt; 'Instruction to record usage of the field by client'
'description' =&gt; 'Instruction to record usage of the field by client',
'locations' =&gt; [
Directive::LOCATION_FIELD,
DirectiveLocation::FIELD,
],
'args' =&gt; [
new FieldArgument([
'name' =&gt; 'details',
'type' =&gt; Type::string(),
'description' =&gt; 'String with additional details of field usage scenario'
'description' =&gt; 'String with additional details of field usage scenario',
'defaultValue' =&gt; ''
])
]
]);
</code></pre>
<p>Directive location can be one of the following values:</p>
<ul>
<li><code>Directive::LOCATION_QUERY</code></li>
<li><code>Directive::LOCATION_MUTATION</code></li>
<li><code>Directive::LOCATION_SUBSCRIPTION</code></li>
<li><code>Directive::LOCATION_FIELD</code></li>
<li><code>Directive::LOCATION_FRAGMENT_DEFINITION</code></li>
<li><code>Directive::LOCATION_FRAGMENT_SPREAD</code></li>
<li><code>Directive::LOCATION_INLINE_FRAGMENT</code></li>
</ul>
<p>See possible directive locations in
<a href="../../reference/#graphqltypedefinitiondirectivelocation"><code>GraphQL\Type\Definition\DirectiveLocation</code></a>.</p>
</div>
</div>
@ -239,7 +253,7 @@ $trackDirective = new Directive([
<a href="../schema/" class="btn btn-neutral float-right" title="Schema">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../input-types/" class="btn btn-neutral" title="Input Types"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../input-types/" class="btn btn-neutral" title="Mutations and Input Types"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -106,7 +111,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -116,6 +121,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -136,7 +145,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -161,7 +180,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -179,8 +198,9 @@
<p>Enumeration types are a special kind of scalar that is restricted to a particular set
of allowed values. </p>
<p>In <strong>graphql-php</strong> enum type is an instance of <code>GraphQL\Type\Definition\EnumType</code>
(or one of it subclasses) which accepts configuration array in constructor:</p>
<pre><code class="php">use GraphQL\Type\Definition\EnumType;
which accepts configuration array in constructor:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' =&gt; 'Episode',
@ -202,10 +222,10 @@ $episodeEnum = new EnumType([
]);
</code></pre>
<p>This example uses <strong>inline</strong> style for Enum Type definition, but you can also use
<a href="../../type-system/#type-definition-styles">inheritance</a>.</p>
<p>This example uses an <strong>inline</strong> style for Enum Type definition, but you can also use
<a href="../#type-definition-styles">inheritance or type language</a>.</p>
<h1 id="configuration-options">Configuration options</h1>
<p>Enum Type constructor accepts array with following options:</p>
<p>Enum Type constructor accepts an array with following options:</p>
<table>
<thead>
<tr>
@ -218,7 +238,7 @@ $episodeEnum = new EnumType([
<tr>
<td>name</td>
<td><code>string</code></td>
<td><strong>Required.</strong> Name of the type. When not set - inferred from array key (read about <a href="#">shorthand field definition</a> below)</td>
<td><strong>Required.</strong> Name of the type. When not set - inferred from array key (read about <a href="#shorthand-definitions">shorthand field definition</a> below)</td>
</tr>
<tr>
<td>description</td>
@ -245,7 +265,7 @@ $episodeEnum = new EnumType([
<tr>
<td>name</td>
<td><code>string</code></td>
<td><strong>Required.</strong> Name of the item. When not set - inferred from array key (read about <a href="#">shorthand field definition</a> below)</td>
<td><strong>Required.</strong> Name of the item. When not set - inferred from array key (read about <a href="#shorthand-definitions">shorthand field definition</a> below)</td>
</tr>
<tr>
<td>value</td>
@ -267,7 +287,10 @@ $episodeEnum = new EnumType([
<h1 id="shorthand-definitions">Shorthand definitions</h1>
<p>If internal representation of enumerated item is the same as item name, then you can use
following shorthand for definition:</p>
<pre><code class="php">$episodeEnum = new EnumType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' =&gt; 'Episode',
'description' =&gt; 'One of the films in the Star Wars Trilogy',
'values' =&gt; ['NEWHOPE', 'EMPIRE', 'JEDI']
@ -275,19 +298,10 @@ following shorthand for definition:</p>
</code></pre>
<p>which is equivalent of:</p>
<pre><code class="php">$episodeEnum = new EnumType([
'name' =&gt; 'Episode',
'description' =&gt; 'One of the films in the Star Wars Trilogy',
'values' =&gt; [
'NEWHOPE' =&gt; 'NEWHOPE',
'EMPIRE' =&gt; 'EMPIRE',
'JEDI' =&gt; 'JEDI'
]
]);
</code></pre>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\EnumType;
<p>which is in turn equivalent of:</p>
<pre><code class="php">$episodeEnum = new EnumType([
$episodeEnum = new EnumType([
'name' =&gt; 'Episode',
'description' =&gt; 'One of the films in the Star Wars Trilogy',
'values' =&gt; [
@ -298,8 +312,11 @@ following shorthand for definition:</p>
]);
</code></pre>
<p>which is in turn equivalent of full form:</p>
<pre><code class="php">$episodeEnum = new EnumType([
<p>which is in turn equivalent of the full form:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\EnumType;
$episodeEnum = new EnumType([
'name' =&gt; 'Episode',
'description' =&gt; 'One of the films in the Star Wars Trilogy',
'values' =&gt; [
@ -311,10 +328,11 @@ following shorthand for definition:</p>
</code></pre>
<h1 id="field-resolution">Field Resolution</h1>
<p>When object field is of Enum Type, field resolver is expected to return internal
<p>When object field is of Enum Type, field resolver is expected to return an internal
representation of corresponding Enum item (<strong>value</strong> in config). <strong>graphql-php</strong> will
then serialize this <strong>value</strong> to <strong>name</strong> to include in response:</p>
<pre><code class="php">use GraphQL\Type\Definition\EnumType;
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\ObjectType;
$episodeEnum = new EnumType([
@ -346,30 +364,34 @@ $heroType = new ObjectType([
}
]
]
])
]);
</code></pre>
<p>Reverse is true when enum is used as input type (e.g. as field argument).
<p>The Reverse is true when the enum is used as input type (e.g. as field argument).
GraphQL will treat enum input as <strong>name</strong> and convert it into <strong>value</strong> before passing to your app.</p>
<p>For example, given object type definition:</p>
<pre><code class="php">$heroType = new ObjectType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$heroType = new ObjectType([
'name' =&gt; 'Hero',
'fields' =&gt; [
'appearsIn' =&gt; [
'type' =&gt; Type::boolean(),
'args' =&gt; [
'episode' =&gt; Type::nonNull($enumType)
]
],
'resolve' =&gt; function($_value, $args) {
return $args['episode'] === 5 ? true : false;
}
]
]
])
]);
</code></pre>
<p>Then following query:</p>
<pre><code>fragment on Hero {
<pre><code class="graphql">fragment on Hero {
appearsInNewHope: appearsIn(NEWHOPE)
appearsInEmpire: appearsIn(EMPIRE)
}

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class=" current">
@ -103,7 +108,7 @@
</li>
<li class="">
<a class="" href="input-types/">Input Types</a>
<a class="" href="input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -113,6 +118,10 @@
<a class="" href="schema/">Schema</a>
</li>
<li class="">
<a class="" href="type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -133,7 +142,17 @@
<li class="toctree-l1">
<a class="" href="../complementary-tools/">Complementary Tools</a>
<a class="" href="../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../reference/">Class Reference</a>
</li>
</ul>
@ -158,7 +177,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -173,11 +192,12 @@
<div class="section">
<h1 id="type-system">Type System</h1>
<p>To start using GraphQL you are expected to implement a type hierarchy and expose it as <a href="../type-system/schema/">Schema</a>. </p>
<p>In <strong>graphql-php</strong> <code>type</code> is an instance of internal class from
<code>GraphQL\Type\Definition</code> namespace: <code>ScalarType</code>, <code>ObjectType</code>, <code>InterfaceType</code>,
<code>UnionType</code>, <code>InputObjectType</code> (or one of it's subclasses).</p>
<p>But most of the types in your schema will be <a href="../type-system/object-types/">object types</a>.</p>
<p>To start using GraphQL you are expected to implement a type hierarchy and expose it as <a href="schema/">Schema</a>. </p>
<p>In graphql-php <strong>type</strong> is an instance of internal class from
<code>GraphQL\Type\Definition</code> namespace: <a href="object-types/"><code>ObjectType</code></a>,
<a href="interfaces/"><code>InterfaceType</code></a>, <a href="unions/"><code>UnionType</code></a>, <a href="input-types/"><code>InputObjectType</code></a>,
<a href="scalar-types/"><code>ScalarType</code></a>, <a href="enum-types/"><code>EnumType</code></a> (or one of subclasses).</p>
<p>But most of the types in your schema will be <a href="object-types/">object types</a>.</p>
<h1 id="type-definition-styles">Type Definition Styles</h1>
<p>Several styles of type definitions are supported depending on your preferences.</p>
<p>Inline definitions:</p>
@ -218,39 +238,29 @@ class MyType extends ObjectType
}
</code></pre>
<p>You can also mix-and-match styles for convenience. For example:</p>
<pre><code class="php">&lt;?php
namespace MyApp;
<p>Using <a href="http://graphql.org/learn/schema/#type-language">GraphQL Type language</a>:</p>
<pre><code class="graphql">schema {
query: Query
mutation: Mutation
}
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
type Query {
greetings(input: HelloInput!): String!
}
class BlogPostType extends ObjectType
{
public function __construct()
{
$config = [
'fields' =&gt; [
'body' =&gt; new ObjectType([
'name' =&gt; 'BlogPostBody',
'fields' =&gt; [
'html' =&gt; Type::string(),
'text' =&gt; Type::string(),
]
])
]
];
parent::__construct($config);
}
input HelloInput {
firstName: String!
lastName: String
}
</code></pre>
<p>Read more about type language definitions in a <a href="type-language/">dedicated docs section</a>.</p>
<h1 id="type-registry">Type Registry</h1>
<p>Every type must be presented in Schema by single instance (<strong>graphql-php</strong>
throws when it discovers several instances with the same <code>name</code> in schema).</p>
<p>Every type must be presented in Schema by a single instance (<strong>graphql-php</strong>
throws when it discovers several instances with the same <strong>name</strong> in the schema).</p>
<p>Therefore if you define your type as separate PHP class you must ensure that only one
instance of that class is added to schema.</p>
<p>Typical way to do this is to create registry of your types:</p>
instance of that class is added to the schema.</p>
<p>The typical way to do this is to create a registry of your types:</p>
<pre><code class="php">&lt;?php
namespace MyApp;
@ -289,10 +299,11 @@ class MyAType extends ObjectType
}
</code></pre>
<p>Obviously you can automate this registry as you wish to reduce boilerplate or even
<p>Obviously, you can automate this registry as you wish to reduce boilerplate or even
introduce Dependency Injection Container if your types have other dependencies.</p>
<p>Alternatively all methods of registry could be static if you prefer - then there is no need
to pass it in constructor - instead just use use <code>TypeRegistry::myAType()</code> in your type definitions.</p>
<p>Alternatively, all methods of the registry could be static - then there is no need
to pass it in constructor - instead just use use <strong>TypeRegistry::myAType()</strong> in your
type definitions.</p>
</div>
</div>
@ -303,7 +314,7 @@ to pass it in constructor - instead just use use <code>TypeRegistry::myAType()</
<a href="object-types/" class="btn btn-neutral float-right" title="Object Types">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../getting-started/" class="btn btn-neutral" title="Getting Started"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../complementary-tools/" class="btn btn-neutral" title="Complementary Tools"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
@ -329,7 +340,7 @@ to pass it in constructor - instead just use use <code>TypeRegistry::myAType()</
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../getting-started/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span><a href="../complementary-tools/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="object-types/" style="color: #fcfcfc">Next &raquo;</a></span>

View File

@ -8,7 +8,7 @@
<link rel="shortcut icon" href="../../img/favicon.ico">
<title>Input Types - graphql-php</title>
<title>Mutations and Input Types - graphql-php</title>
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../../css/theme.css" type="text/css" />
@ -17,7 +17,7 @@
<script>
// Current page data
var mkdocs_page_name = "Input Types";
var mkdocs_page_name = "Mutations and Input Types";
var mkdocs_page_input_path = "type-system\\input-types.md";
var mkdocs_page_url = "/type-system/input-types/";
</script>
@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,9 +96,12 @@
</li>
<li class=" current">
<a class="current" href="./">Input Types</a>
<a class="current" href="./">Mutations and Input Types</a>
<ul class="subnav">
<li class="toctree-l3"><a href="#mutations">Mutations</a></li>
<li class="toctree-l3"><a href="#about-input-and-output-types">About Input and Output Types</a></li>
@ -116,6 +124,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -136,7 +148,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -161,11 +183,11 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
<li>Input Types</li>
<li>Mutations and Input Types</li>
<li class="wy-breadcrumbs-aside">
</li>
@ -175,12 +197,53 @@
<div role="main">
<div class="section">
<h1 id="about-input-and-output-types">About Input and Output Types</h1>
<p>GraphQL receives data from clients via <a href="../object-types/#field-arguments">Field Arguments</a>.</p>
<p>Both - fields and arguments require <strong>type</strong> 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.</p>
<p>Consequentially all types in GraphQL are of two categories: <strong>input</strong> and <strong>output</strong>.</p>
<h1 id="mutations">Mutations</h1>
<p>Mutation is just a field of a regular <a href="../object-types/">Object Type</a> with arguments.
For GraphQL PHP runtime there is no difference between query fields with arguments and mutations.
They are executed <a href="http://facebook.github.io/graphql/#sec-Mutation">almost</a> identically.
To some extent, Mutation is just a convention described in the GraphQL spec.</p>
<p>Here is an example of a mutation operation:</p>
<pre><code class="graphql">mutation CreateReviewForEpisode($ep: EpisodeInput!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
</code></pre>
<p>To execute such a mutation, you need <strong>Mutation</strong> type <a href="../schema/">at the root of your schema</a>:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$myMutationType = new ObjectType([
'name' =&gt; 'Mutation',
'fields' =&gt; [
// List of mutations:
'createReview' =&gt; [
'args' =&gt; [
'episode' =&gt; Type::nonNull($episodeInputType),
'review' =&gt; Type::nonNull($reviewInputType)
],
'type' =&gt; new ObjectType([
'name' =&gt; 'CreateReviewOutput',
'fields' =&gt; [
'stars' =&gt; ['type' =&gt; Type::int()],
'commentary' =&gt; ['type' =&gt; Type::string()]
]
]),
],
// ... other mutations
]
]);
</code></pre>
<p>As you can see, the only difference from regular object type is the semantics of field names
(verbs vs nouns).</p>
<p>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.</p>
<h1 id="about-input-and-output-types">About Input and Output Types</h1>
<p>All types in GraphQL are of two categories: <strong>input</strong> and <strong>output</strong>.</p>
<ul>
<li>
<p><strong>Output</strong> types (or field types) are: <a href="../scalar-types/">Scalar</a>, <a href="../enum-types/">Enum</a>, <a href="../object-types/">Object</a>,
@ -190,17 +253,21 @@ output.</p>
<p><strong>Input</strong> types (or argument types) are: <a href="../scalar-types/">Scalar</a>, <a href="../enum-types/">Enum</a>, InputObject</p>
</li>
</ul>
<p>Obviously <a href="../lists-and-nonnulls/">NonNull and List</a> types belong to both categories depending on their
<p>Obviously, <a href="../lists-and-nonnulls/">NonNull and List</a> types belong to both categories depending on their
inner type.</p>
<p>Until now all examples of field <strong>arguments</strong> in this documentation were of <a href="../scalar-types/">Scalar</a> or
<a href="../enum-types/">Enum</a> types. But you can also easily pass complex objects. </p>
<p>This is particularly valuable in the case of mutations, where input data might be rather complex.</p>
<a href="../enum-types/">Enum</a> types. But you can also pass complex objects. </p>
<p>This is particularly valuable in case of mutations, where input data might be rather complex.</p>
<h1 id="input-object-type">Input Object Type</h1>
<p>GraphQL specification defines Input Object Type for complex inputs. It is similar to ObjectType
except that it's fields have no <strong>args</strong> or <strong>resolve</strong> options and their <strong>type</strong> must be input type.</p>
<p>In <strong>graphql-php</strong> Input Object Type is an instance of <code>GraphQL\Type\Definition\InputObjectType</code>
<p>In graphql-php <strong>Input Object Type</strong> is an instance of <code>GraphQL\Type\Definition\InputObjectType</code>
(or one of it subclasses) which accepts configuration array in constructor:</p>
<pre><code class="php">$filters = new InputObjectType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\InputObjectType;
$filters = new InputObjectType([
'name' =&gt; 'StoryFiltersInput',
'fields' =&gt; [
'author' =&gt; [
@ -221,7 +288,7 @@ except that it's fields have no <strong>args</strong> or <strong>resolve</strong
<p>Every field may be of other InputObjectType (thus complex hierarchies of inputs are possible)</p>
<h1 id="configuration-options">Configuration options</h1>
<p>Constructor of InputObjectType accepts array with only 3 options:</p>
<p>The constructor of InputObjectType accepts array with only 3 options:</p>
<table>
<thead>
<tr>
@ -238,8 +305,8 @@ except that it's fields have no <strong>args</strong> or <strong>resolve</strong
</tr>
<tr>
<td>fields</td>
<td><code>array</code> or <code>callback</code> returning <code>array</code></td>
<td><strong>Required</strong>. Array describing object fields (see below).</td>
<td><code>array</code> or <code>callable</code></td>
<td><strong>Required</strong>. An array describing object fields or callable returning such an array (see below).</td>
</tr>
<tr>
<td>description</td>
@ -266,7 +333,7 @@ except that it's fields have no <strong>args</strong> or <strong>resolve</strong
<tr>
<td>type</td>
<td><code>Type</code></td>
<td><strong>Required.</strong> Instance of one of <a href="../input-types/">Input Types</a> (<code>Scalar</code>, <code>Enum</code>, <code>InputObjectType</code> + any combination of those with <code>NonNull</code> and <code>List</code> modifiers)</td>
<td><strong>Required.</strong> Instance of one of <a href="./">Input Types</a> (<strong>Scalar</strong>, <strong>Enum</strong>, <strong>InputObjectType</strong> + any combination of those with <strong>nonNull</strong> and <strong>listOf</strong> modifiers)</td>
</tr>
<tr>
<td>description</td>
@ -282,7 +349,11 @@ except that it's fields have no <strong>args</strong> or <strong>resolve</strong
</table>
<h1 id="using-input-object-type">Using Input Object Type</h1>
<p>In the example above we defined our InputObjectType. Now let's use it in one of field arguments:</p>
<pre><code class="php">$queryType = new ObjectType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$queryType = new ObjectType([
'name' =&gt; 'Query',
'fields' =&gt; [
'stories' =&gt; [

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -112,7 +117,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -122,6 +127,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -142,7 +151,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -167,7 +186,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -185,8 +204,9 @@
<p>An Interface is an abstract type that includes a certain set of fields that a
type must include to implement the interface.</p>
<p>In <strong>graphql-php</strong> interface type is an instance of <code>GraphQL\Type\Definition\InterfaceType</code>
(or one of it subclasses) which accepts configuration array in constructor:</p>
<pre><code class="php">use GraphQL\Type\Definition\InterfaceType;
(or one of its subclasses) which accepts configuration array in a constructor:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\Type;
$character = new InterfaceType([
@ -213,9 +233,9 @@ $character = new InterfaceType([
</code></pre>
<p>This example uses <strong>inline</strong> style for Interface definition, but you can also use<br />
<a href="../../type-system/#type-definition-styles">inheritance</a>.</p>
<a href="../#type-definition-styles">inheritance or type language</a>.</p>
<h1 id="configuration-options">Configuration options</h1>
<p>Constructor of InterfaceType accepts an array. Below is a full list of allowed options:</p>
<p>The constructor of InterfaceType accepts an array. Below is a full list of allowed options:</p>
<table>
<thead>
<tr>
@ -233,7 +253,7 @@ $character = new InterfaceType([
<tr>
<td>fields</td>
<td><code>array</code></td>
<td><strong>Required.</strong> List of fields required to be defined by interface implementors. Same as <a href="#">Fields for Object Type</a></td>
<td><strong>Required.</strong> List of fields required to be defined by interface implementors. Same as <a href="../object-types/#field-configuration-options">Fields for Object Type</a></td>
</tr>
<tr>
<td>description</td>
@ -242,14 +262,18 @@ $character = new InterfaceType([
</tr>
<tr>
<td>resolveType</td>
<td><code>callback</code> returning instance of <code>ObjectType</code></td>
<td><strong>function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)</strong> Any <code>callable</code> that receives <code>$value</code> from resolver of the parent field and returns concrete interface implementor for that <code>$value</code>.</td>
<td><code>callback</code></td>
<td><strong>function($value, $context, <a href="../../reference/#graphqltypedefinitionresolveinfo">ResolveInfo</a> $info)</strong><br> Receives <strong>$value</strong> from resolver of the parent field and returns concrete interface implementor for this <strong>$value</strong>.</td>
</tr>
</tbody>
</table>
<h1 id="implementing-interface">Implementing interface</h1>
<p>To implement the Interface simply add it to <strong>interfaces</strong> array of Object Type definition:</p>
<pre><code class="php">$humanType = new ObjectType([
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
'name' =&gt; 'Human',
'fields' =&gt; [
'id' =&gt; [
@ -272,7 +296,7 @@ $character = new InterfaceType([
<p>The only exception is when object's field type is more specific than the type of this field defined in interface
(see <a href="#covariant-return-types-for-interface-fields">Covariant return types for interface fields</a> below)</p>
<h1 id="covariant-return-types-for-interface-fields">Covariant return types for interface fields</h1>
<p>Object types implementing interface may change field type to more specific.
<p>Object types implementing interface may change the field type to more specific.
Example:</p>
<pre><code>interface A {
field1: A
@ -285,8 +309,12 @@ type B implements A {
<h1 id="sharing-interface-fields">Sharing Interface fields</h1>
<p>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:</p>
<pre><code class="php">$humanType = new ObjectType([
sense to reuse field definitions of Interface in Object Types:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
'name' =&gt; 'Human',
'interfaces' =&gt; [
$character
@ -299,10 +327,10 @@ sense to re-use field definitions of Interface in Object Types:</p>
]);
</code></pre>
<p>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
<p>In this case, field definitions are created only once (as a part of Interface Type) and then
reused by all interface implementors. It can save several microseconds and kilobytes + ensures that
field definitions of Interface and implementors are always in sync.</p>
<p>Yet it creates a problem with resolution of such fields. There are two ways how shared fields could
<p>Yet it creates a problem with the resolution of such fields. There are two ways how shared fields could
be resolved:</p>
<ol>
<li>
@ -310,17 +338,17 @@ be resolved:</p>
<strong>resolve</strong> option to field definition in Interface itself.</p>
</li>
<li>
<p>If field resolution varies from implementor to implementor - you can specify <strong>resolveField</strong>
option in <a href="../../type-system/object-types/#configuration-options">Object Type config</a> and handle field
<p>If field resolution varies for different implementations - you can specify <strong>resolveField</strong>
option in <a href="../object-types/#configuration-options">Object Type config</a> and handle field
resolutions there
(Note: <strong>resolve</strong> option in field definition has precedence over <strong>resolveField</strong> option in object type definition)</p>
</li>
</ol>
<h1 id="interface-role-in-data-fetching">Interface role in data fetching</h1>
<p>The only responsibility of interface in Data Fetching process is to return concrete Object Type
for given <code>$value</code> in <strong>resolveType</strong>. Then resolution of fields is delegated to resolvers of this
for given <strong>$value</strong> in <strong>resolveType</strong>. Then resolution of fields is delegated to resolvers of this
concrete Object Type.</p>
<p>If <strong>resolveType</strong> option is omitted, <strong>graphql-php</strong> will loop through all interface implementors and
<p>If a <strong>resolveType</strong> option is omitted, graphql-php will loop through all interface implementors and
use their <strong>isTypeOf</strong> callback to pick the first suitable one. This is obviously less efficient
than single <strong>resolveType</strong> call. So it is recommended to define <strong>resolveType</strong> whenever possible.</p>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -100,7 +105,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -110,6 +115,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -130,7 +139,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -155,7 +174,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -191,14 +210,15 @@ $userType = new ObjectType([
]);
</code></pre>
<p>Resolvers for such fields are expected to return <code>array</code> or instance of PHP internal <code>Traversable</code>
interface (<code>null</code> is allowed by default too). </p>
<p>Resolvers for such fields are expected to return <strong>array</strong> or instance of PHP's built-in <strong>Traversable</strong>
interface (<strong>null</strong> is allowed by default too). </p>
<p>If returned value is not of one of these types - <strong>graphql-php</strong> will add an error to result
and set field value to <code>null</code> (only if field is nullable, see below for non-null fields).</p>
and set the field value to <strong>null</strong> (only if the field is nullable, see below for non-null fields).</p>
<h1 id="non-null-fields">Non-Null fields</h1>
<p>By default in GraphQL every field can have <code>null</code> value. To indicate that some field always
returns <code>non-null</code> value - use <code>GraphQL\Type\Definition\Type::nonNull()</code> modifier:</p>
<pre><code class="php">use GraphQL\Type\Definition\Type;
<p>By default in GraphQL, every field can have a <strong>null</strong> value. To indicate that some field always
returns <strong>non-null</strong> value - use <code>GraphQL\Type\Definition\Type::nonNull()</code> modifier:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$humanType = new ObjectType([
@ -220,10 +240,10 @@ $humanType = new ObjectType([
]);
</code></pre>
<p>If resolver of non-null field returns <code>null</code>, <strong>graphql-php</strong> will add an error to
result and exclude whole object from output (error will bubble to first nullable parent
field which will be set to <code>null</code>).</p>
<p>Read section on <a href="#">Data Fetching</a> for details.</p>
<p>If resolver of non-null field returns <strong>null</strong>, graphql-php will add an error to
result and exclude the whole object from the output (an error will bubble to first
nullable parent field which will be set to <strong>null</strong>).</p>
<p>Read the section on <a href="../../data-fetching/">Data Fetching</a> for details.</p>
</div>
</div>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -118,7 +123,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -128,6 +133,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -148,7 +157,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -173,7 +192,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -188,9 +207,9 @@
<div class="section">
<h1 id="object-type-definition">Object Type Definition</h1>
<p>Object Type is the most frequently used primitive in typical GraphQL application.</p>
<p>Conceptually Object Type is a collection of Fields. Each field in turn
has it's own type which allows to build complex hierarchies.</p>
<p>Object Type is the most frequently used primitive in a typical GraphQL application.</p>
<p>Conceptually Object Type is a collection of Fields. Each field, in turn,
has its own type which allows building complex hierarchies.</p>
<p>In <strong>graphql-php</strong> object type is an instance of <code>GraphQL\Type\Definition\ObjectType</code>
(or one of it subclasses) which accepts configuration array in constructor:</p>
<pre><code class="php">&lt;?php
@ -243,7 +262,7 @@ $blogStory = new ObjectType([
</code></pre>
<p>This example uses <strong>inline</strong> style for Object Type definitions, but you can also use<br />
<a href="../../type-system/#type-definition-styles">inheritance</a>.</p>
<a href="../#type-definition-styles">inheritance or type language</a>.</p>
<h1 id="configuration-options">Configuration options</h1>
<p>Object type constructor expects configuration array. Below is a full list of available options:</p>
<table>
@ -262,8 +281,8 @@ $blogStory = new ObjectType([
</tr>
<tr>
<td>fields</td>
<td><code>array</code> or <code>callback</code> returning <code>array</code></td>
<td><strong>Required</strong>. Array describing object fields. See <a href="#field-definitions">Fields</a> section below for expected structure of each array entry. See also section on <a href="#">Circular types</a> for explanation of when to use callback for this option.</td>
<td><code>array</code> or <code>callable</code></td>
<td><strong>Required</strong>. An array describing object fields or callable returning such an array. See <a href="#field-definitions">Fields</a> section below for expected structure of each array entry. See also the section on <a href="#recurring-and-circular-types">Circular types</a> for an explanation of when to use callable for this option.</td>
</tr>
<tr>
<td>description</td>
@ -272,18 +291,18 @@ $blogStory = new ObjectType([
</tr>
<tr>
<td>interfaces</td>
<td><code>array</code> or <code>callback</code> returning <code>array</code></td>
<td>List of interfaces implemented by this type. See <a href="../../type-system/interface-types">Interface Types</a> for details. See also section on <a href="#">Circular types</a> for explanation of when to use callback for this option.</td>
<td><code>array</code> or <code>callable</code></td>
<td>List of interfaces implemented by this type or callable returning such a list. See <a href="../interfaces/">Interface Types</a> for details. See also the section on <a href="#recurring-and-circular-types">Circular types</a> for an explanation of when to use callable for this option.</td>
</tr>
<tr>
<td>isTypeOf</td>
<td><code>callback</code> returning <code>boolean</code></td>
<td><strong>function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)</strong> Expected to return <code>true</code> if <code>$value</code> qualifies for this type (see section about <a href="#">Abstract Type Resolution</a> for explanation).</td>
<td><code>callable</code></td>
<td><strong>function($value, $context, <a href="../../reference/#graphqltypedefinitionresolveinfo">ResolveInfo</a> $info)</strong><br> Expected to return <strong>true</strong> if <strong>$value</strong> qualifies for this type (see section about <a href="../interfaces/#interface-role-in-data-fetching">Abstract Type Resolution</a> for explanation).</td>
</tr>
<tr>
<td>resolveField</td>
<td><code>callback</code> returning <code>mixed</code></td>
<td><strong>function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)</strong> Given the <code>$value</code> of this type it is expected to return value for field defined in <code>$info-&gt;fieldName</code>. Good place to define type-specific strategy for field resolution. See section on <a href="#">Data Fetching</a> for details.</td>
<td><code>callable</code></td>
<td><strong>function($value, $args, $context, <a href="../../reference/#graphqltypedefinitionresolveinfo">ResolveInfo</a> $info)</strong><br> Given the <strong>$value</strong> of this type, it is expected to return value for a field defined in <strong>$info-&gt;fieldName</strong>. A good place to define a type-specific strategy for field resolution. See section on <a href="../../data-fetching/">Data Fetching</a> for details.</td>
</tr>
</tbody>
</table>
@ -301,22 +320,27 @@ $blogStory = new ObjectType([
<tr>
<td>name</td>
<td><code>string</code></td>
<td><strong>Required.</strong> Name of the field. When not set - inferred from <strong>fields</strong> array key (read about <a href="#">shorthand field definition</a> below)</td>
<td><strong>Required.</strong> Name of the field. When not set - inferred from <strong>fields</strong> array key (read about <a href="#shorthand-field-definitions">shorthand field definition</a> below)</td>
</tr>
<tr>
<td>type</td>
<td><code>Type</code></td>
<td><strong>Required.</strong> Instance of internal or custom type. Note: type must be represented by single instance within schema (see also <a href="#">Type Registry</a>)</td>
<td><strong>Required.</strong> An instance of internal or custom type. Note: type must be represented by a single instance within one schema (see also <a href="../#type-registry">Type Registry</a>)</td>
</tr>
<tr>
<td>args</td>
<td><code>array</code></td>
<td>Array of possible type arguments. Each entry is expected to be an array with keys: <strong>name</strong>, <strong>type</strong>, <strong>description</strong>, <strong>defaultValue</strong>. See <a href="#field-arguments">Field Arguments</a> section below.</td>
<td>An array of possible type arguments. Each entry is expected to be an array with keys: <strong>name</strong>, <strong>type</strong>, <strong>description</strong>, <strong>defaultValue</strong>. See <a href="#field-arguments">Field Arguments</a> section below.</td>
</tr>
<tr>
<td>resolve</td>
<td><code>callback</code></td>
<td><strong>function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info)</strong> Given the <code>$value</code> of this type it is expected to return value for current field. See section on <a href="#">Data Fetching</a> for details</td>
<td><code>callable</code></td>
<td><strong>function($value, $args, $context, <a href="../../reference/#graphqltypedefinitionresolveinfo">ResolveInfo</a> $info)</strong><br> Given the <strong>$value</strong> of this type, it is expected to return actual value of the current field. See section on <a href="../../data-fetching/">Data Fetching</a> for details</td>
</tr>
<tr>
<td>complexity</td>
<td><code>callable</code></td>
<td><strong>function($childrenComplexity, $args)</strong><br> Used to restrict query complexity. The feature is disabled by default, read about <a href="../../security/#query-complexity-analysis">Security</a> to use it.</td>
</tr>
<tr>
<td>description</td>
@ -350,7 +374,7 @@ Each argument is an array with following options:</p>
<tr>
<td>type</td>
<td><code>Type</code></td>
<td><strong>Required.</strong> Instance of one of <a href="../input-types/">Input Types</a> (<code>scalar</code>, <code>enum</code>, <code>InputObjectType</code> + any combination of those with <code>nonNull</code> and <code>listOf</code> modifiers)</td>
<td><strong>Required.</strong> Instance of one of <a href="../input-types/">Input Types</a> (<strong>scalar</strong>, <strong>enum</strong>, <strong>InputObjectType</strong> + any combination of those with <strong>nonNull</strong> and <strong>listOf</strong> modifiers)</td>
</tr>
<tr>
<td>description</td>
@ -379,7 +403,7 @@ Each argument is an array with following options:</p>
]
</code></pre>
<p>which is in turn equivalent of full form:</p>
<p>which is in turn equivalent of the full form:</p>
<pre><code class="php">'fields' =&gt; [
['name' =&gt; 'id', 'type' =&gt; Type::id()],
['name' =&gt; 'fieldName', 'type' =&gt; $fieldName]
@ -390,10 +414,14 @@ Each argument is an array with following options:</p>
<h1 id="recurring-and-circular-types">Recurring and circular types</h1>
<p>Almost all real-world applications contain recurring or circular types.
Think user friends or nested comments for example. </p>
<p><strong>graphql-php</strong> allows such types, but you have to use <code>callback</code> in
<p><strong>graphql-php</strong> allows such types, but you have to use <code>callable</code> in
option <strong>fields</strong> (and/or <strong>interfaces</strong>).</p>
<p>For example:</p>
<pre><code class="php">$userType = null;
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;
$userType = null;
$userType = new ObjectType([
'name' =&gt; 'User',
@ -410,7 +438,7 @@ $userType = new ObjectType([
]);
</code></pre>
<p>Same example for <a href="#">inheritance style of type definitions</a> using <a href="#">TypeRegistry</a>:</p>
<p>Same example for <a href="../#type-definition-styles">inheritance style of type definitions</a> using <a href="../#type-registry">TypeRegistry</a>:</p>
<pre><code class="php">&lt;?php
namespace MyApp;
@ -456,14 +484,14 @@ class MyTypes
<h1 id="field-resolution">Field Resolution</h1>
<p>Field resolution is the primary mechanism in <strong>graphql-php</strong> for returning actual data for your fields.
It is implemented using <code>resolveField</code> callback in type definition or <code>resolve</code>
callback in field definition (which has precedence).</p>
<p>Read section on <a href="">Data Fetching</a> for complete description of this process.</p>
It is implemented using <strong>resolveField</strong> callable in type definition or <strong>resolve</strong>
callable in field definition (which has precedence).</p>
<p>Read the section on <a href="../../data-fetching/">Data Fetching</a> for a complete description of this process.</p>
<h1 id="custom-metadata">Custom Metadata</h1>
<p>All types in <strong>graphql-php</strong> accept configuration array. In some cases you may be interested in
<p>All types in <strong>graphql-php</strong> accept configuration array. In some cases, you may be interested in
passing your own metadata for type or field definition.</p>
<p><strong>graphql-php</strong> preserves original configuration array in every type or field instance in
public property <code>$config</code>. Use it to implement app-level mappings and definitions.</p>
public property <strong>$config</strong>. Use it to implement app-level mappings and definitions.</p>
</div>
</div>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -100,7 +105,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -110,6 +115,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -130,7 +139,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -155,7 +174,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -171,8 +190,9 @@
<h1 id="built-in-scalar-types">Built-in Scalar Types</h1>
<p>GraphQL specification describes several built-in scalar types. In <strong>graphql-php</strong> they are
exposed as static methods of <code>GraphQL\Type\Definition\Type</code> class:</p>
<pre><code class="php">use GraphQL\Type\Definition\Type;
exposed as static methods of <a href="../../reference/#graphqltypedefinitiontype"><code>GraphQL\Type\Definition\Type</code></a> class:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\Type;
// Built-in Scalar types:
Type::string(); // String type
@ -182,38 +202,39 @@ Type::boolean(); // Boolean type
Type::id(); // ID type
</code></pre>
<p>Those methods return instances of <code>GraphQL\Type\Definition\ScalarType</code> (actually one of it subclasses).
Use them directly in type definitions, or wrap in your <a href="../../type-system/#type-registry">TypeRegistry</a>
<p>Those methods return instances of <code>GraphQL\Type\Definition\ScalarType</code> (actually one of subclasses).
Use them directly in type definitions, or wrap in your <a href="../#type-registry">TypeRegistry</a>
(if you use one).</p>
<h1 id="writing-custom-scalar-types">Writing Custom Scalar Types</h1>
<p>In addition to built-in scalars, you can define your own scalar types with additional validation.
Typical examples of such types are: <code>Email</code>, <code>Date</code>, <code>Url</code>, etc.</p>
<p>In order to implement your own type you must understand how scalars are presented in GraphQL.
Typical examples of such types are <strong>Email</strong>, <strong>Date</strong>, <strong>Url</strong>, etc.</p>
<p>In order to implement your own type, you must understand how scalars are presented in GraphQL.
GraphQL deals with scalars in following cases:</p>
<ol>
<li>
<p>When converting <strong>internal representation</strong> of value returned by your app (e.g. stored in database
or hardcoded in source code) to <strong>serialized</strong> representation included in response.</p>
<p>When converting <strong>internal representation</strong> of value returned by your app (e.g. stored in a database
or hardcoded in the source code) to <strong>serialized</strong> representation included in the response.</p>
</li>
<li>
<p>When converting <strong>input value</strong> passed by client in variables along with GraphQL query to
<p>When converting <strong>input value</strong> passed by a client in variables along with GraphQL query to
<strong>internal representation</strong> of your app.</p>
</li>
<li>
<p>When converting <strong>input literal value</strong> hardcoded in GraphQL query (e.g. field argument value) to
<strong>internal representation</strong> of your app.</p>
the <strong>internal representation</strong> of your app.</p>
</li>
</ol>
<p>Those cases are covered by methods <code>serialize</code>, <code>parseValue</code> and <code>parseLiteral</code> of abstract <code>ScalarType</code>
class respectively.</p>
<p>Here is an example of simple <code>Email</code> type:</p>
<p>Here is an example of a simple <strong>Email</strong> type:</p>
<pre><code class="php">&lt;?php
namespace MyApp;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Utils;
use GraphQL\Utils\Utils;
class EmailType extends ScalarType
{
@ -232,8 +253,11 @@ 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(&quot;Could not serialize following value as email: &quot; . Utils::printSafe($value));
// }
// return $this-&gt;parseValue($value);
}
@ -246,7 +270,7 @@ class EmailType extends ScalarType
public function parseValue($value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \UnexpectedValueException(&quot;Cannot represent value as email: &quot; . Utils::printSafe($value));
throw new Error(&quot;Cannot represent following value as email: &quot; . Utils::printSafeJson($value));
}
return $value;
}

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -91,7 +96,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -111,8 +116,21 @@
<li class="toctree-l3"><a href="#configuration-options">Configuration Options</a></li>
<li class="toctree-l3"><a href="#using-config-class">Using config class</a></li>
<li class="toctree-l3"><a href="#lazy-loading-of-types">Lazy loading of types</a></li>
<li class="toctree-l3"><a href="#schema-validation">Schema Validation</a></li>
</ul>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -133,7 +151,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -158,7 +186,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -173,28 +201,31 @@
<div class="section">
<h1 id="schema-definition">Schema Definition</h1>
<p>Schema is a container of your type hierarchy, which accepts root types in constructor and provides
<p>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.</p>
<p>In <strong>graphql-php</strong> schema is an instance of <code>GraphQL\Schema</code> which accepts configuration array
in constructor:</p>
<pre><code class="php">$schema = new Schema([
<p>In <strong>graphql-php</strong> schema is an instance of <a href="../../reference/#graphqltypeschema"><code>GraphQL\Type\Schema</code></a>
which accepts configuration array in a constructor:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Schema;
$schema = new Schema([
'query' =&gt; $queryType,
'mutation' =&gt; $mutationType,
]);
</code></pre>
<p>See possible constructor options <a href="#configuration-options">below</a></p>
<p>See possible constructor options <a href="#configuration-options">below</a>.</p>
<h1 id="query-and-mutation-types">Query and Mutation types</h1>
<p>Schema consists of two root types:</p>
<p>The schema consists of two root types:</p>
<ul>
<li><code>Query</code> type is a surface of your read API</li>
<li><code>Mutation</code> type (optional) exposes write API by declaring all possible mutations in your app. </li>
<li><strong>Query</strong> type is a surface of your read API</li>
<li><strong>Mutation</strong> type (optional) exposes write API by declaring all possible mutations in your app. </li>
</ul>
<p>Query and Mutation types are regular <a href="../object-types/">object types</a> containing root-level fields
of your API:</p>
<pre><code class="php">use GraphQL\Type\Definition\ObjectType;
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Schema;
$queryType = new ObjectType([
'name' =&gt; 'Query',
@ -204,7 +235,7 @@ $queryType = new ObjectType([
'resolve' =&gt; function() {
return 'Hello World!';
}
]
],
'hero' =&gt; [
'type' =&gt; $characterInterface,
'args' =&gt; [
@ -222,8 +253,8 @@ $queryType = new ObjectType([
$mutationType = new ObjectType([
'name' =&gt; 'Mutation',
'fields' =&gt; [
'createReviewForEpisode' =&gt; [
'type' =&gt; $createReviewForEpisodeMutation,
'createReview' =&gt; [
'type' =&gt; $createReviewOutput,
'args' =&gt; [
'episode' =&gt; $episodeEnum,
'review' =&gt; $reviewInputObject
@ -236,14 +267,15 @@ $mutationType = new ObjectType([
]);
</code></pre>
<p>Keep in mind that other than the special meaning of declaring surface area of your API,
<p>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 <a href="../object-types/">object type</a>, and their fields work
exactly the same way.</p>
<p><strong>Mutation</strong> type is also just a regular object type. The difference is in semantics.
Field names of Mutation type are usually verbs and they almost always have arguments - quite often
with complex input values (see <a href="../input-types/">Input Types</a> for details).</p>
with complex input values (see <a href="../input-types/">Mutations and Input Types</a> for details).</p>
<h1 id="configuration-options">Configuration Options</h1>
<p>Schema constructor expects an array with following options:</p>
<p>Schema constructor expects an instance of <a href="../../reference/#graphqltypeschemaconfig"><code>GraphQL\Type\SchemaConfig</code></a>
or an array with following options:</p>
<table>
<thead>
<tr>
@ -271,15 +303,110 @@ with complex input values (see <a href="../input-types/">Input Types</a> for det
<tr>
<td>directives</td>
<td><code>Directive[]</code></td>
<td>Full list of <a href="../directives/">directives</a> supported by your schema. By default contains built-in <code>@skip</code> and <code>@include</code> directives.<br><br> If you pass your own directives and still want to use built-in directives - add them explicitly. For example: <code>array_merge(GraphQL::getInternalDirectives(), [$myCustomDirective]</code></td>
<td>A full list of <a href="../directives/">directives</a> supported by your schema. By default, contains built-in <strong>@skip</strong> and <strong>@include</strong> directives.<br><br> If you pass your own directives and still want to use built-in directives - add them explicitly. For example:<br><br> <em>array_merge(GraphQL::getStandardDirectives(), [$myCustomDirective]);</em></td>
</tr>
<tr>
<td>types</td>
<td><code>ObjectType[]</code></td>
<td>List of object types which cannot be detected by <strong>graphql-php</strong> 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 <code>resolveType</code> 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.</td>
<td>List of object types which cannot be detected by <strong>graphql-php</strong> 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 <strong>resolveType</strong> 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.</td>
</tr>
<tr>
<td>typeLoader</td>
<td><code>callable</code></td>
<td><strong>function($name)</strong> 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.</td>
</tr>
</tbody>
</table>
<h1 id="using-config-class">Using config class</h1>
<p>If you prefer fluid interface for config with auto-completion in IDE and static time validation,
use <a href="../../reference/#graphqltypeschemaconfig"><code>GraphQL\Type\SchemaConfig</code></a> instead of an array:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\SchemaConfig;
use GraphQL\Type\Schema;
$config = SchemaConfig::create()
-&gt;setQuery($myQueryType)
-&gt;setTypeLoader($myTypeLoader);
$schema = new Schema($config);
</code></pre>
<h1 id="lazy-loading-of-types">Lazy loading of types</h1>
<p>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 the schema. </p>
<p>In this case, it is recommended to pass <strong>typeLoader</strong> option to schema constructor and define all
of your object <strong>fields</strong> as callbacks.</p>
<p>Type loading concept is very similar to PHP class loading, but keep in mind that <strong>typeLoader</strong> must
always return the same instance of a type.</p>
<p>Usage example:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Schema;
class Types
{
private $types = [];
public function get($name)
{
if (!isset($this-&gt;types[$name])) {
$this-&gt;types[$name] = $this-&gt;{$name}();
}
return $this-&gt;types[$name];
}
private function MyTypeA()
{
return new ObjectType([
'name' =&gt; 'MyTypeA',
'fields' =&gt; function() {
return [
'b' =&gt; ['type' =&gt; $this-&gt;get('MyTypeB')]
];
}
]);
}
private function MyTypeB()
{
// ...
}
}
$registry = new Types();
$schema = new Schema([
'query' =&gt; $registry-&gt;get('Query'),
'typeLoader' =&gt; function($name) use ($registry) {
return $registry-&gt;get($name);
}
]);
</code></pre>
<h1 id="schema-validation">Schema Validation</h1>
<p>By default, the schema is created with only shallow validation of type and field definitions<br />
(because validation requires full schema scan and is very costly on bigger schemas).</p>
<p>But there is a special method <strong>assertValid()</strong> on schema instance which throws
<code>GraphQL\Error\InvariantViolation</code> exception when it encounters any error, like:</p>
<ul>
<li>Invalid types used for fields/arguments</li>
<li>Missing interface implementations</li>
<li>Invalid interface implementations</li>
<li>Other schema errors...</li>
</ul>
<p>Schema validation is supposed to be used in CLI commands or during build step of your app.
Don't call it in web requests in production. </p>
<p>Usage example:</p>
<pre><code class="php">&lt;?php
try {
$schema = new GraphQL\Type\Schema([
'query' =&gt; $myQueryType
]);
$schema-&gt;assertValid();
} catch (GraphQL\Error\InvariantViolation $e) {
echo $e-&gt;getMessage();
}
</code></pre>
</div>
</div>
@ -287,7 +414,7 @@ with complex input values (see <a href="../input-types/">Input Types</a> for det
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../../executing-queries/" class="btn btn-neutral float-right" title="Executing Queries">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../type-language/" class="btn btn-neutral float-right" title="Using Type Language">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../directives/" class="btn btn-neutral" title="Directives"><span class="icon icon-circle-arrow-left"></span> Previous</a>
@ -319,7 +446,7 @@ with complex input values (see <a href="../input-types/">Input Types</a> for det
<span><a href="../directives/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../../executing-queries/" style="color: #fcfcfc">Next &raquo;</a></span>
<span style="margin-left: 15px"><a href="../type-language/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>

View File

@ -0,0 +1,313 @@
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="../../img/favicon.ico">
<title>Using Type Language - graphql-php</title>
<link href='https://fonts.googleapis.com/css?family=Lato:400,700|Roboto+Slab:400,700|Inconsolata:400,700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="../../css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../css/theme_extra.css" type="text/css" />
<link rel="stylesheet" href="../../css/highlight.css">
<script>
// Current page data
var mkdocs_page_name = "Using Type Language";
var mkdocs_page_input_path = "type-system\\type-language.md";
var mkdocs_page_url = "/type-system/type-language/";
</script>
<script src="../../js/jquery-2.1.1.min.js"></script>
<script src="../../js/modernizr-2.8.3.min.js"></script>
<script type="text/javascript" src="../../js/highlight.pack.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-nav-search">
<a href="../.." class="icon icon-home"> graphql-php</a>
<div role="search">
<form id ="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
<ul class="current">
<li class="toctree-l1">
<a class="" href="../..">About</a>
</li>
<li class="toctree-l1">
<a class="" href="../../getting-started/">Getting Started</a>
</li>
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
<a class="" href="../">Introduction</a>
</li>
<li class="">
<a class="" href="../object-types/">Object Types</a>
</li>
<li class="">
<a class="" href="../scalar-types/">Scalar Types</a>
</li>
<li class="">
<a class="" href="../enum-types/">Enumeration Types</a>
</li>
<li class="">
<a class="" href="../lists-and-nonnulls/">Lists and Non-Null</a>
</li>
<li class="">
<a class="" href="../interfaces/">Interfaces</a>
</li>
<li class="">
<a class="" href="../unions/">Unions</a>
</li>
<li class="">
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
<a class="" href="../directives/">Directives</a>
</li>
<li class="">
<a class="" href="../schema/">Schema</a>
</li>
<li class=" current">
<a class="current" href="./">Using Type Language</a>
<ul class="subnav">
<li class="toctree-l3"><a href="#defining-your-schema">Defining your schema</a></li>
<li class="toctree-l3"><a href="#defining-resolvers">Defining resolvers</a></li>
<li class="toctree-l3"><a href="#performance-considerations">Performance considerations</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1">
<a class="" href="../../executing-queries/">Executing Queries</a>
</li>
<li class="toctree-l1">
<a class="" href="../../data-fetching/">Fetching Data</a>
</li>
<li class="toctree-l1">
<a class="" href="../../error-handling/">Handling Errors</a>
</li>
<li class="toctree-l1">
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
</div>
&nbsp;
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="top navigation">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../..">graphql-php</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="../..">Docs</a> &raquo;</li>
<li>Type Definitions &raquo;</li>
<li>Using Type Language</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main">
<div class="section">
<h1 id="defining-your-schema">Defining your schema</h1>
<p><a href="http://graphql.org/learn/schema/#type-language">Type language</a> is a convenient way to define your schema,
especially with IDE autocompletion and syntax validation.</p>
<p>Here is a simple schema defined in GraphQL type language (e.g. in a separate <strong>schema.graphql</strong> file):</p>
<pre><code class="graphql">schema {
query: Query
mutation: Mutation
}
type Query {
greetings(input: HelloInput!): String!
}
input HelloInput {
firstName: String!
lastName: String
}
</code></pre>
<p>In order to create schema instance out of this file, use
<a href="../../reference/#graphqlutilsbuildschema"><code>GraphQL\Utils\BuildSchema</code></a>:</p>
<pre><code class="php">&lt;?php
use GraphQL\Utils\BuildSchema;
$contents = file_get_contents('schema.graphql');
$schema = BuildSchema::build($contents);
</code></pre>
<p>By default, such schema is created without any resolvers. As a result, it doesn't support <strong>Interfaces</strong> and <strong>Unions</strong>
because it is impossible to resolve actual implementations during execution.</p>
<p>Also, we have to rely on <a href="../../data-fetching/#default-field-resolver">default field resolver</a> and <strong>root value</strong> in
order to execute a query against this schema.</p>
<h1 id="defining-resolvers">Defining resolvers</h1>
<p>In order to enable <strong>Interfaces</strong>, <strong>Unions</strong> and custom field resolvers you can pass the second argument:
<strong>type config decorator</strong> to schema builder. </p>
<p>It accepts default type config produced by the builder and is expected to add missing options like
<a href="../interfaces/#configuration-options"><strong>resolveType</strong></a> for interface types or
<a href="../object-types/#configuration-options"><strong>resolveField</strong></a> for object types.</p>
<pre><code class="php">&lt;?php
use GraphQL\Utils\BuildSchema;
$typeConfigDecorator = function($typeConfig, $typeDefinitionNode) {
$name = $typeConfig['name'];
// ... add missing options to $typeConfig based on type $name
return $typeConfig;
};
$contents = file_get_contents('schema.graphql');
$schema = BuildSchema::build($contents, $typeConfigDecorator);
</code></pre>
<h1 id="performance-considerations">Performance considerations</h1>
<p>Method <strong>build()</strong> produces a <a href="../schema/#lazy-loading-of-types">lazy schema</a>
automatically, so it works efficiently even with very large schemas.</p>
<p>But parsing type definition file on each request is suboptimal, so it is recommended to cache
intermediate parsed representation of the schema for the production environment:</p>
<pre><code class="php">&lt;?php
use GraphQL\Language\Parser;
use GraphQL\Utils\BuildSchema;
use GraphQL\Utils\AST;
$cacheFilename = 'cached_schema.php';
if (!file_exists($cacheFilename)) {
$document = Parser::parse(file_get_contents('./schema.graphql'));
file_put_contents($cacheFilename, &quot;&lt;?php\nreturn &quot; . var_export($document-&gt;toArray(), true));
} else {
$document = AST::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well
}
$typeConfigDecorator = function () {};
$schema = BuildSchema::build($document, $typeConfigDecorator);
</code></pre>
</div>
</div>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../../executing-queries/" class="btn btn-neutral float-right" title="Executing Queries">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../schema/" class="btn btn-neutral" title="Schema"><span class="icon icon-circle-arrow-left"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="http://www.mkdocs.org">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" style="cursor: pointer">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../schema/" style="color: #fcfcfc;">&laquo; Previous</a></span>
<span style="margin-left: 15px"><a href="../../executing-queries/" style="color: #fcfcfc">Next &raquo;</a></span>
</span>
</div>
<script src="../../js/theme.js"></script>
</body>
</html>

View File

@ -59,7 +59,12 @@
<li class="toctree-l1">
<span class="caption-text">Type System</span>
<a class="" href="../../complementary-tools/">Complementary Tools</a>
</li>
<li class="toctree-l1">
<span class="caption-text">Type Definitions</span>
<ul class="subnav">
<li class="">
@ -100,7 +105,7 @@
</li>
<li class="">
<a class="" href="../input-types/">Input Types</a>
<a class="" href="../input-types/">Mutations and Input Types</a>
</li>
<li class="">
@ -110,6 +115,10 @@
<a class="" href="../schema/">Schema</a>
</li>
<li class="">
<a class="" href="../type-language/">Using Type Language</a>
</li>
</ul>
</li>
@ -130,7 +139,17 @@
<li class="toctree-l1">
<a class="" href="../../complementary-tools/">Complementary Tools</a>
<a class="" href="../../security/">Security</a>
</li>
<li class="toctree-l1">
<a class="" href="../../how-it-works/">How it works</a>
</li>
<li class="toctree-l1">
<a class="" href="../../reference/">Class Reference</a>
</li>
</ul>
@ -155,7 +174,7 @@
<li>Type System &raquo;</li>
<li>Type Definitions &raquo;</li>
@ -171,15 +190,18 @@
<h1 id="union-type-definition">Union Type Definition</h1>
<p>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.</p>
The value of Union Type is actually a value of one of included Object Types.</p>
<p>In <strong>graphql-php</strong> union type is an instance of <code>GraphQL\Type\Definition\UnionType</code>
(or one of it subclasses) which accepts configuration array in constructor:</p>
<pre><code class="php">$searchResultType = new UnionType([
(or one of its subclasses) which accepts configuration array in a constructor:</p>
<pre><code class="php">&lt;?php
use GraphQL\Type\Definition\UnionType;
$searchResultType = new UnionType([
'name' =&gt; 'SearchResult',
'types' =&gt; [
MyTypes::story(),
MyTypes::user()
];
],
'resolveType' =&gt; function($value) {
if ($value-&gt;type === 'story') {
return MyTypes::story();
@ -191,9 +213,9 @@ Value of Union Type is actually a value of one of included Object Types.</p>
</code></pre>
<p>This example uses <strong>inline</strong> style for Union definition, but you can also use<br />
<a href="../../type-system/#type-definition-styles">inheritance</a>.</p>
<a href="../#type-definition-styles">inheritance or type language</a>.</p>
<h1 id="configuration-options">Configuration options</h1>
<p>Constructor of UnionType accepts an array. Below is a full list of allowed options:</p>
<p>The constructor of UnionType accepts an array. Below is a full list of allowed options:</p>
<table>
<thead>
<tr>
@ -220,8 +242,8 @@ Value of Union Type is actually a value of one of included Object Types.</p>
</tr>
<tr>
<td>resolveType</td>
<td><code>callback</code> returning instance of <code>ObjectType</code></td>
<td><strong>function($value, $context, GraphQL\Type\Definition\ResolveInfo $info)</strong> Any <code>callable</code> that receives <code>$value</code> from resolver of the parent field and returns Object Type for that <code>$value</code>.</td>
<td><code>callback</code></td>
<td><strong>function($value, $context, <a href="../../reference/#graphqltypedefinitionresolveinfo">ResolveInfo</a> $info)</strong><br> Receives <strong>$value</strong> from resolver of the parent field and returns concrete Object Type for this <strong>$value</strong>.</td>
</tr>
</tbody>
</table>
@ -232,7 +254,7 @@ Value of Union Type is actually a value of one of included Object Types.</p>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<a href="../input-types/" class="btn btn-neutral float-right" title="Input Types">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../input-types/" class="btn btn-neutral float-right" title="Mutations and Input Types">Next <span class="icon icon-circle-arrow-right"></span></a>
<a href="../interfaces/" class="btn btn-neutral" title="Interfaces"><span class="icon icon-circle-arrow-left"></span> Previous</a>