graphql-php/executing-queries/index.html

522 lines
20 KiB
HTML
Raw Normal View History

<!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>Executing Queries - 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 = "Executing Queries";
var mkdocs_page_input_path = "executing-queries.md";
var mkdocs_page_url = "/executing-queries/";
</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 current">
<a class="current" href="./">Executing Queries</a>
<ul class="subnav">
<li class="toctree-l2"><a href="#using-facade-method">Using Facade Method</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="#custom-validation-rules">Custom Validation Rules</a></li>
</ul>
</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>Executing Queries</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main">
<div class="section">
<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 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::executeQuery(
$schema,
$queryString,
$rootValue = null,
$context = null,
$variableValues = null,
$operationName = null,
$fieldResolver = null,
$validationRules = null
);
</code></pre>
<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>
<th>Argument</th>
<th>Type</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>schema</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>
</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>variableValues</td>
<td><code>array</code></td>
<td>Map of variable values passed along with query string. See section on <a href="http://graphql.org/learn/queries/#variables">query variables on official GraphQL website</a></td>
</tr>
<tr>
<td>operationName</td>
<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="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>
<footer>
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
<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/type-language/" class="btn btn-neutral" title="Using Type Language"><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="../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>
</span>
</div>
<script src="../js/theme.js"></script>
</body>
</html>