A PHP port of GraphQL reference implementation



CI Coverage Status Latest Stable Version

This is a PHP implementation of the GraphQL specification based on the reference implementation in JavaScript.


Via composer:

composer require webonyx/graphql-php


Full documentation is available at https://webonyx.github.io/graphql-php or in the docs directory.

If you don't know what GraphQL is, visit the official website first.


There are several ready examples in the examples directory, with a specific README file per example.


This project follows Semantic Versioning 2.0.0.

Elements that belong to the public API of this package are marked with the @api PHPDoc tag. Those elements are thus guaranteed to be stable within major versions. All other elements are not part of this backwards compatibility guarantee and may change between minor or patch versions.


This project exists thanks to all the people who contribute. [Contribute].



Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]



  • Lazy loading of types

    Lazy loading of types

    Implements #425 Proof of concept of full support for lazy loading of types.

    In a nutshell, you can substitute a callable any place that you would ordinarily supply a Type, and it won't be executed by the library until it is actually needed.

    For example, you can create a Types class that looks like this:

    class Types {
    	public static function get(string $classname)
    		return function() use ($classname) {
    			return static::fromCache($classname);
    	protected static function fromCache(string $classname) {
    		$parts = explode("\\", $classname);
    		$cacheName = strtolower(preg_replace('~Type$~', '', $parts[count($parts) - 1]));
    		$type = null;
    		if (!isset(self::$types[$cacheName])) {
    			if (class_exists($classname)) {
    				$type = new $classname();
    			self::$types[$cacheName] = $type;
    		$type = self::$types[$cacheName];
    		if (!$type) {
    			throw new Exception("Unknown graphql type: " . $classname);
    		return $type;
        public static function currency() { return static::get(CurrencyType::class);}
        // ... I explicitly stub out these type methods for the benefit of intellisense and [stanning](https://github.com/phpstan/phpstan), but they're not necessary

    And then your field/arg definitions look the same as usual:

    	'currency' => [
    		'type' => Types::currency(), // this won't load until it is specifically needed!
    		'description' => 'A currency record',

    It may be difficult to imagine this being of any appreciable benefit for small or toy programs, but in my real project I dynamically generate my mutation types (using this) and doing even a small mutation triggers a flood of activity and the instantiation of 656 types(!).

    With this change, that number drops to 1.

    I have run this in the profiler: without lazy loading with lazy loading

    For me, this equates to a savings of around a quarter of a second and 3MB of memory.

    So, what do you think? It's only around 50 lines of mostly trivial code. If you think it looks promising I'll start in on tests and documentation and further polishing.

    opened by shmax 49
  • Implement PSR-7 RequestInterface support

    Implement PSR-7 RequestInterface support

    ServerRequestInterface is not needed, parent RequestInterface is sufficient
    Replaced custom PSR-7 test stubs with nyholm/psr-7 implementation
    Fixed reading body contents

    • ServerRequestInterface extends RequestInterface so for this case I think it's not a BC break.
    • Rephrasing exception message might be considered a BC break I guess.
    opened by simPod 33
  • Executor performance optimization

    Executor performance optimization

    Hi. First, thank you for the great library! We use it to power our API at Scuk.cz and it's been a smooth ride.

    Recently, however, we've discovered poor performance for some of the queries the frontend service sends to the GraphQL endpoint. Over time our schema got pretty big (currently it consists of ~300 types /half of which are object types/ and ~1000 resolvable fields on object types). So did the queries (one of the pages in our app queries ~200 fields).

    We successfully refactored GraphQL schema so that types & fields are created lazily. Also we started caching parsed AST. This got us nice speed improvements. After these I've started to look at performance of the Executor. It costs us more than 150ms per request for some queries. This is the call graph of GraphQL endpoint for such query (library calls are highlighted):

    GraphQL call graph

    I've started digging in the code and found some easy to improve functions (e.g. Executor::shouldIncludeNode()). But I estimate these would shave off only couple of milliseconds. So I've started to work on a new executor:

    • separated compilation & execution phases
      • first, AST is transformed into an intermediate representation (= instructions) that is better suitable for manipulation and exection
      • then, the instructions are processed sequentially (I suppose sequential execution should be more machine-friendly than jumping between tens of functions and callbacks, therefore perform better)
    • instruction pipeline can be manipulated with during the execution (new instructions are pushed to the front or back)
    • compiled instructions could be cached instead of an AST
      • in the future, they could be compiled down to PHP code for even better performance (as some templating engines, DI containers etc. do)

    This is still a work in progress and will need some time before the new executor passes the test suite. Yet, what do you think about this? :)

    Questions & notes:

    1. ValueNode interface doc comment says that VariableNode is a ValueNode. But VariableNode does not implement it. Is it intentional, or a bug?
    2. This might be quite a lot of changes. Is there a way to check code style? (I've run composer run lint, however, PHP-CS reported issues even with current files.)
    3. Current executor works with results as arrays. But this is a problem for JSON serialization if the array remains empty (there is a workaround converting empty array to stdClass). I started new executor to work with stdClasses instead, because I need pass by reference semantics, also it fixes JSON-serialization-related issue from the start. But this would be big breaking change. Should I continue with stdClasses, or use arrays?
    4. I started typehinting all parameters of all new methods. But then I realized the library still supports older PHP versions. Is there a plan to drop old versions support?
    5. ResolveInfo is tightly coupled to AST traversal execution model. After the compilation, AST is no longer relevant for new executor. It could include needed AST nodes in instructions, however, it defies the point of the compilation step.
    opened by jakubkulhan 33
  • Add support for setting extensions from resolvers.

    Add support for setting extensions from resolvers.

    This adds an API to ResolveInfo which allows resolvers to directly add items to be returned to the client in the extensions element of the response body.

    see http://facebook.github.io/graphql/October2016/#sec-Response-Format

    opened by aelnagger 32
  • Fix namenode type / rewrite Printer

    Fix namenode type / rewrite Printer

    An alternative fix for #655, the infamous NamedTypeNode NameNode / string debacle.

    Took me a while to understand, but all the trouble was being caused by the unusual algorithm used to print ASTs. It tied into Visitor::visit, and starting at the leaf nodes, would stomp over properties with strings so that it could concatenate everything into a big string. We noticed this happening on the NamedTypeNode in particular, but actually this was happening with all of the nodes.

    Once I understood what was happening, I was able to rearrange the algorithm into a more conventional top-down recursive one that does not "edit" any nodes, nor do any illegal writes. While I was at it, I corrected a number of type annotations. PHPStan is now happy. Note that this change is not as dramatic as it might look; all of the callbacks from the old leave section in Printer were simply ported into a big switch statement. I didn't change any of the core logic.

    Interestingly, performance seems to improve with these changes, though I'm not sure why.

    master: https://blackfire.io/profiles/a1b07e4f-cba2-4327-84c5-c42e7559d8b2/graph

    this branch: https://blackfire.io/profiles/755fec5e-3bf3-491a-b8d0-8a6d78a30fd6/graph

    opened by shmax 30
  • Horizontal eval for lazy loading same-type objects

    Horizontal eval for lazy loading same-type objects

    When I first learned about GraphQL there was a performance chapter. If every relation loads every single relation, it requires many queries to load a few levels of data, even if the actual data is only on the last level. The solution was to lazy load objects: first collect ids (horizontal), and then load all objects at once, and then evaluate the next level.

    Just in case. This query:

    query {
        user {
            reservations {
                resource {
                    sport {

    would take 20 queries to find 10 reservations > 10x 1 resource > 10x 1 sport. If it would eval horizontally, it would do 2 queries: load 10 resources, then load 10 sports. (Maybe not 2 levels, but even 1 could be a big difference.)

    Is that a thing? It seems like the query is evaled vertically first, so it loads the entire 1 reservation (1 resource + 1 sport), and then the entire 1 next (1 resource + 1 sport) etc.

    opened by rudiedirkx 26
  • Update graphql spec to April2016

    Update graphql spec to April2016

    There is a new version of the GraphQL spec April2016.

    It changed some parts in the introspection. I might have time to open a PR for this, but probably at earliest in two weeks.

    opened by danez 25
  • Add AmpPromiseAdapter

    Add AmpPromiseAdapter

    Had some time today so I implemented a PromiseAdapter for Amp. Note that I just wrote blindly what seemed to make some sense and it's not tested at all. I'll try to use it in my project when I get to reimplementing my GraphQL part to async. And of course I need to add some unit tests. All of this might take a while (a few months), I'm just posting this here in case someone was looking for it and was willing to help me out with testing.

    Code reviews are of course welcome.

    opened by enumag 23
  • Feedback on Experimental Executor

    Feedback on Experimental Executor

    Please post your feedback here on the new experimental executor introduced in https://github.com/webonyx/graphql-php/pull/314

    Especially interested in following questions:

    1. Do you see a performance improvement on your queries? How much on average?
    2. Do you experience any issues / unexpected behavior with it?
    community feedback wanted 
    opened by vladar 21
  • Mutations with Relay (React)

    Mutations with Relay (React)

    I'm using the laravel-graphql, and created an issue but I'm not sure if it's something that should actually be created here (still trying to wrap my head around GraphQL).

    When working with Relay, it expects that mutations have only one argument called input. Looking at the todo example, in the schema.json file it has that field listed as an INPUT_OBJECT type. I created the following (again, using laravel-graphql), but I'm unable to get the fields from the InputObjectType. Am I doing something wrong?

    namespace App\GraphQL\Mutations;
    use GraphQL;
    use App\Models\Customer;
    use GraphQL\Type\Definition\Type;
    use GraphQL\Type\Definition\InputObjectType;
    use Folklore\GraphQL\Support\Mutation;
    class UpdateCustomerEmail extends Mutation
         * Associated GraphQL Type.
         * @return mixed
        public function type()
            return GraphQL::type('customerPayload');
         * Available arguments for mutation.
         * @return array
        public function args()
            return [
                'input' => [
                    'name' => 'input',
                    'type' => new InputObjectType([
                        'name' => 'updateCustomerEmailInput',
                        'fields' => [
                            'entity_id' => [
                                'name' => 'entity_id',
                                'type' => Type::nonNull(Type::string())
                            'email' => [
                                'name' => 'email',
                                'type' => Type::nonNull(Type::string())
         * Resolve mutation.
         * @param  string $root
         * @param  array $args
         * @return Customer
        public function resolve($root, $args, $info)
            // $root is null, $args is an empty array and nothing in $info gives me the 
            // variables passed in the request
            $customer = Customer::find($args['input']['entity_id']); // $args['input'] is not set
            $customer->email = $args['input']['email'];
            return $customer;
    opened by chrissm79 21
  • Performance improvements

    Performance improvements

    I've been messing around with this project a bit lately, and I've had some trouble with performance. The GraphQL executor does quite a bit of unnecessary work when it resolves fields. Since it operates recursively, larger lists have a really bad impact on performance. I have tried to fix some of the bottlenecks by memoizing objects and values that can be re-used.

    I'd like to hear what you think about this approach. According to the Blackfire profiler the response was 2x faster for a large query and 1.5x faster for one I use in my app. You can check out my fork here: https://github.com/johanobergman/graphql-php

    opened by johanobergman 21
  • Rate-Limit: Possibility to retrieve the QueryComplexity

    Rate-Limit: Possibility to retrieve the QueryComplexity

    Hello together,

    there are requirements to build a rate-limit system based on the query complexity & not based on request-hits. This blog-post describes this behaivor: https://shopify.engineering/rate-limiting-graphql-apis-calculating-query-complexity To make this happen we need to calculate the QueryComplexity before we execute the query.

    This can be done by executing the QueryComplexity rule before the "executeQuery" method. In the past there was also a getter to retrieve the calculated QueryComplexity on the validator.

    Bonus: The used query complexity after the execution can be lower then the requested QueryComplexity. For example you request a list of 10 but the system have only 5. In a perfect world we would charge back the 5 to much requested nodes. While such a sub-feature would be nice, it is for sure no requirement for a first change.

    Introducing of QueryComplexity getter: https://github.com/webonyx/graphql-php/pull/531 Issue got created based on following discussion: https://github.com/webonyx/graphql-php/discussions/1025


    help wanted 
    opened by kinimodmeyer 2
  • Comply with graphql-over-http specification

    Comply with graphql-over-http specification

    It would be great if the standard server were compliant with the GraphQL-over-HTTP specification.

    The test suite could be done in a way that is reusable by other servers: https://github.com/graphql/graphql-over-http/issues/57

    opened by spawnia 0
  • Ignore Introspection queries in QueryComplexity rule

    Ignore Introspection queries in QueryComplexity rule

    Followup from https://github.com/webonyx/graphql-php/discussions/1203

    The QueryComplexity rule should ignore introspection query. This way you can set the max query complexity very low and still allow introspections to happen.

    Introspection has a complexity of around 181.

    opened by ruudk 1
  • Do not store standard types statically but keep them on the Schema instead

    Do not store standard types statically but keep them on the Schema instead

    When working with 2 schemas that have different standard types this becomes problematic.

    For example, I have a schema that uses a custom ID type, but the other wants to use the default.

    I can imagine this is not easily possible currently because of the way types are resolvable without a Schema (#1149).

    enhancement BC break 
    opened by ruudk 1
  • Version docs

    Version docs

    We currently have only one version of docs deployed, always reflecting the latest changes in master. This is inaccurate for users of older versions: https://github.com/webonyx/graphql-php/issues/1178 https://github.com/webonyx/graphql-php/issues/944

    We can try to set up https://github.com/jimporter/mike for versioning.

    opened by spawnia 0
  • v14.11.6(Apr 13, 2022)

  • v14.11.5(Jan 24, 2022)

  • v14.11.4(Jan 20, 2022)

  • v14.11.3(Nov 19, 2021)

  • v14.11.2(Nov 18, 2021)

  • v14.11.1(Nov 15, 2021)

  • v14.11.0(Oct 29, 2021)

  • v14.10.0(Oct 28, 2021)

  • v14.9.0(Jun 15, 2021)

  • v14.8.0(Jun 1, 2021)

  • v14.7.0(May 17, 2021)

  • v14.6.4(May 11, 2021)

  • v14.6.3(May 10, 2021)

  • v14.6.2(Apr 23, 2021)

  • v14.6.1(Mar 29, 2021)

  • v14.6.0(Mar 29, 2021)

  • v14.5.1(Feb 5, 2021)

  • v14.5.0(Jan 23, 2021)


    • Implement support for interfaces implementing interfaces (#740), huge kudos to @Kingdutch





    • Reify AST node types and remove unneeded nullability (#751)
    Source code(tar.gz)
    Source code(zip)
  • v14.4.1(Jan 23, 2021)


    • Allow pushing nodes to NodeList via []= (#767)
    • Fix signature of Error\FormattedError::prepareFormatter() to address PHP8 deprecation (#742)
    • Do not add errors key to result when errors discarded by custom error handler (#766)
    Source code(tar.gz)
    Source code(zip)
  • v14.4.0(Dec 3, 2020)

    • Fixed SchemaPrinter so that it uses late static bindings when extended (#747)
    • Parse DirectiveDefinitionNode->locations as NodeList<NamedNode> (fixes AST::fromArray conversion) (#723)
    • Parse Parser::implementsInterfaces as NodeList<NamedTypeNode> (fixes AST::fromArray conversion)
    • Fix signature of Parser::unionMemberTypes to match actual NodeList<NamedTypeNode>
    Source code(tar.gz)
    Source code(zip)
  • v14.3.0(Aug 23, 2020)


    • Allow typeLoader to return a type thunk (#687)


    • Read getParsedBody() instead of getBody() when Request is ServerRequest (#715)
    • Fix default get/set behavior on InputObjectField and FieldDefinition (#716)
    Source code(tar.gz)
    Source code(zip)
  • v14.2.0(Aug 14, 2020)

  • v14.1.1(Jul 21, 2020)

  • v14.1.0(Jul 21, 2020)


    • Add partial parse functions for const variants (#693)


    • Differentiate between client-safe and non-client-safe errors in scalar validation (#706)
    • Proper type hints for IntValueNode (#691)


    • Ensure NamedTypeNode::$name is always a NameNode (#695)
    • Visitor: simplify getVisitFn (#694)
    • Replace function calls with type casts (#692)
    • Fix "only booleans are allowed" errors (#659)
    Source code(tar.gz)
    Source code(zip)
  • v14.0.2(Jul 7, 2020)

  • v14.0.1(Jul 2, 2020)

    Bug fixes:

    • Fix for "Invalid AST Node: false" error (#685)
    • Fix for: Argument defaults with integer/float values crashes introspection query (#679)
    • Fix double Error wrapping when parsing variables (#688)


    • Do not use call_user_func or call_user_func_array (#676)
    • Codestyle and static analysis improvements (#648, #690)
    Source code(tar.gz)
    Source code(zip)
  • v0.13.9(Jul 2, 2020)

  • v14.0.0(Jun 21, 2020)

    This release brings several breaking changes. Please refer to UPGRADE document for details.

    • BREAKING/BUGFIX: Strict coercion of scalar types (#278)
    • BREAKING/BUGFIX: Spec-compliance: Fixed ambiguity with null variable values and default values (#274)
    • BREAKING: Removed deprecated directive introspection fields (onOperation, onFragment, onField)
    • BREAKING: GraphQL\Deferred now extends GraphQL\Executor\Promise\Adapter\SyncPromise
    • BREAKING: renamed several types of dangerous/breaking changes (returned by BreakingChangesFinder)
    • BREAKING: Renamed GraphQL\Error\Debug to GraphQL\Error\DebugFlag.
    • BREAKING: Debug flags in GraphQL\Executor\ExecutionResult, GraphQL\Error\FormattedError and GraphQL\Server\ServerConfig do not accept boolean value anymore but int only.
    • BREAKING: $positions in GraphQL\Error\Error constructor are not nullable anymore. Same can be expressed by passing an empty array.

    Notable features and improvements:

    • Compliant with the GraphQL specification June 2018 Edition
    • Support repeatable directives (#643)
    • Perf: support lazy type definitions (#557)
    • Simplified Deferred implementation (now allows chaining like promises, #581)
    • Support SDL Validation and other schema validation improvements (e.g. #492)
    • Added promise adapter for Amp (#551)
    • Query plan utility improvements (#513, #632)

    Other noteworthy changes:

    • Allow retrieving query complexity once query has been completed (#316)
    • Allow input types to be passed in from variables using \stdClass instead of associative arrays (#535)
    • Support UTF-16 surrogate pairs within string literals (#554, #556)
    • Having an empty string in deprecationReason will now print the @deprecated directive (only a null deprecationReason won't print the @deprecated directive).
    • Deprecated Experimental executor (#397)

    Also some bugs fixed, heavily investe in PHPStan for static analysis.

    Special thanks to @simPod, @spawnia and @shmax for their major contributions!

    Source code(tar.gz)
    Source code(zip)
  • v0.13.8(Aug 25, 2019)

  • v0.13.7(Aug 23, 2019)

    • Added retrieving query complexity once query has been completed (#316)
    • Allow input types to be passed in from variables using \stdClass instead of associative arrays (#535)
    Source code(tar.gz)
    Source code(zip)
Monorepo of the PoP project, including: a server-side component model in PHP, a GraphQL server, a GraphQL API plugin for WordPress, and a website builder

PoP PoP is a monorepo containing several projects. The GraphQL API for WordPress plugin GraphQL API for WordPress is a forward-looking and powerful Gr

Leonardo Losoviz 252 Sep 7, 2022
Syntax to query GraphQL through URL params, which grants a GraphQL API the capability to be cached on the server.

Field Query Syntax to query GraphQL through URL params, which grants a GraphQL API the capability to be cached on the server. Install Via Composer com

PoP 4 Jan 7, 2022
Pure PHP implementation of GraphQL Server – Symfony Bundle

Symfony GraphQl Bundle This is a bundle based on the pure PHP GraphQL Server implementation This bundle provides you with: Full compatibility with the

null 288 Sep 12, 2022
GraPHPinator ⚡ 🌐 ⚡ Easy-to-use & Fast GraphQL server implementation for PHP

Easy-to-use & Fast GraphQL server implementation for modern PHP. Includes features from latest draft, middleware directives and modules with extra functionality.

Infinityloop.dev 33 Apr 27, 2022
GraphQL implementation with power of Laravel

Laravel GraphQL Use Facebook GraphQL with Laravel 5.2 >=. It is based on the PHP implementation here. You can find more information about GraphQL in t

Studionet 56 Mar 9, 2022
Test your PHP GraphQL server in style, with Pest!

Pest GraphQL Plugin Test your GraphQL API in style, with Pest! Installation Simply install through Composer! composer require --dev miniaturebase/pest

Minibase 14 Aug 9, 2022
Pure PHP realization of GraphQL protocol

Looking for Maintainers! Unfortunatelly, we cannot longer support this package and are looking for someone to take the ownership. Currently Only PRs w

null 716 Aug 1, 2022
Create REST and GraphQL APIs, scaffold Jamstack webapps, stream changes in real-time.

API Platform is a next-generation web framework designed to easily create API-first projects without compromising extensibility and flexibility: Desig

API Platform 7.6k Sep 19, 2022
This bundle provides tools to build a complete GraphQL server in your Symfony App.

OverblogGraphQLBundle This Symfony bundle provides integration of GraphQL using webonyx/graphql-php and GraphQL Relay. It also supports: batching with

Webedia - Overblog 708 Sep 13, 2022
GraphQL Bundle for Symfony 2.

Symfony 2 GraphQl Bundle Use Facebook GraphQL with Symfony 2. This library port laravel-graphql. It is based on the PHP implementation here. Installat

Sergey Varibrus 36 Nov 1, 2020
Laravel wrapper for Facebook's GraphQL

Laravel GraphQL Use Facebook's GraphQL with Laravel 6.0+. It is based on the PHP port of GraphQL reference implementation. You can find more informati

Mikk Mihkel Nurges 1.9k Sep 22, 2022
A framework for serving GraphQL from Laravel

Lighthouse A framework for serving GraphQL from Laravel Lighthouse is a GraphQL framework that integrates with your Laravel application. It takes the

NuWave Commerce 3k Sep 19, 2022
EXPERIMENTAL plugin extending WPGraphQL to support querying (Gutenberg) Blocks as data, using Server Side Block registries to map Blocks to the GraphQL Schema.

WPGraphQL Block Editor This is an experimental plugin to work toward compatiblity between the WordPress Gutenberg Block Editor and WPGraphQL, based on

WPGraphQL 27 Aug 18, 2022
🍞🧑‍🍳 An on-the-fly GraphQL Schema generator from Eloquent models for Laravel.

An on-the-fly GraphQL Schema generator from Eloquent models for Laravel. Installation Quickstart Model schemas Installation This package requires PHP

Scrn 97 Aug 21, 2022
Add Price Including tax for Magento's "cart" GraphQl query

Comwrap_GraphQlCartPrices Add Price Including tax for Magento's "cart" GraphQl query Query will looks like following: items { id __typenam

Comwrap 1 Dec 2, 2021
A Statamic Pro addon that provides alternative GraphQL queries for collections, entries and global sets.

Statamic Enhanced GraphQL A Statamic CMS GraphQL Addon that provides alternative GraphQL queries for collections, entries and global sets. ⚠️ This is

Grischa Erbe 2 Dec 7, 2021
Place where I record all knowledge gained for GraphQL from Laracasts & other tutorials.

Knowledge from Laracasts series: https://laracasts.com/series/graphql-with-laravel-and-vue What is GraphQL It is a query language for your API, and it

Nikola 0 Dec 26, 2021
The server component of API Platform: hypermedia and GraphQL APIs in minutes

API Platform Core API Platform Core is an easy to use and powerful system to create hypermedia-driven REST and GraphQL APIs. It is a component of the

API Platform 2.1k Sep 16, 2022
Performance monitoring Lighthouse with GraphQL Hive.

Lighthouse GraphQL Hive GraphQL Hive can measure and collect data against all your GraphQL operations and generate analytics on them. This package aim

Alex Bouma 20 Aug 20, 2022