GithubHelp home page GithubHelp logo

digiaonline / graphql-php Goto Github PK

View Code? Open in Web Editor NEW
218.0 218.0 11.0 1.69 MB

A PHP7 implementation of the GraphQL specification.

Home Page: https://facebook.github.io/graphql/

License: MIT License

PHP 100.00%
api graphql php php-library php7

graphql-php's People

Contributors

acelot avatar cgrice avatar crisu83 avatar fubhy avatar hugovk avatar hungneox avatar jalle19 avatar monkeywithacupcake avatar serafimarts avatar spawnia avatar symm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-php's Issues

Validation rules

We need to add support for validation using the Visitor pattern.

The following rules have been implemented:

  • ExecutableDefinitions
  • FieldOnCorrectType
  • FragmentsOnCompositeTypes
  • KnownArgumentNames
  • KnownDirectives
  • KnownFragmentNames
  • KnownTypeNames
  • LoneAnonymousOperation
  • NoFragmentCycles
  • NoUndefinedVariables
  • NoUnusedFragments
  • NoUnusedVariables
  • OverlappingFieldsCanBeMerged
  • PossibleFragmentSpreads
  • ProvidedNonNullArguments
  • ScalarLeafs
  • SingleFieldSubscriptions
  • UniqueArgumentNames
  • UniqueDirectivesPerLocation
  • UniqueFragmentNames
  • UniqueInputFieldNames
  • UniqueOperationNames
  • UniqueVariableNames
  • ValuesOfCorrectType
  • VariablesAreInputTypes
  • VariablesDefaultValueAllowed
  • VariablesInAllowedPosition

Refactor definition builder usage

I want to refactor the definition builder instantiation to get rid of the creator concept used in both schema building and schema extension.

Steps for achieving this:

  • Move logic for collecting definitions from context to the main class
  • Store the definition info in an info class
  • Create the DefinitionBuilder using the info class
  • Pass the DefinitionBuilder and info instances to the context
  • Use the DefinitionBuilder and info to get the desired result
  • Remove the DefinitionBuilderCreator concept
  • Fix dependency injection

Move coercers into classes

Currently, the coercers are namespaced functions. It would be better to convert them into classes and inject them through a CoercerProvider. This way the developer could easily override them.

Namespace naming conventions

@mathewrapid raised a question about the namespace naming conventions. Currently, we use Behavior for traits and Contract for interfaces, but maybe we should do some research on this and see how other popular libraries name their namespaces.

[Question] Maturity?

My team has been using Youshido GraphQL for a project over the last 9 months or so. It gets the job done, but it's slow, not documented well, and PRs take forever to get merged and released. So my team has been debating the pros/cons of forking it and driving it in a more performant direction.

One of the performance-related PRs on that project appears to have come from the developers of this project… which leads me to ask some questions:

  1. Is this project ready for heavy production loads by teams outside of yourselves?

  2. Is there a migration path from Youshido to this one?

  3. What kind of stability/support would another team be able to expect from this package?

  4. Are you open to third-party PRs, and is there a reasonably straightforward process for contributing back upstream?

In other words, how mature is this as an open-source project?

Type resolver tests

I added initial support for resolving types for union and interfaces when using SDL in #187. However, I didn't write any tests for it yet, so that needs to be done.

Introspection

We need to add basic support for introspection queries.

Error location and path are missing

Currently, we cannot get the location nor the path from errors that happen inside resolvers. We need this in order to present the error as a whole to the user. I had to mark the three last test cases in the QueryTest as incomplete because of this missing feature (#137).

GraphQL language parser

The plan is to use the CPP GraphQL parser. It can be wrapped as a PHP extension, so it saves us the trouble of writing our own parser. There is even a ready-made wrapper for it, but some tests seemed to fail while I tried to build an extension with the latest version of the parser.

Validation Bug

What did I do?

Use graphql() with validation for MutationTest::testSimpleMutation

public function testSimpleMutation()
{
    $schema = GraphQLSchema([
        'mutation' =>
            new ObjectType([
                'name'   => 'M',
                'fields' => [
                    'greeting' => [
                        'type'    => GraphQLString(),
                        'resolve' => function ($source, $args, $context, $info) {
                            return sprintf('Hello %s.', $args['name']);
                        },
                        'args'    => [
                            'name' => [
                                'type' => GraphQLString()
                            ]
                        ]
                    ]
                ]
            ])
    ]);

    $source = '
    mutation M($name: String) {
        greeting(name:$name)
    }';

    $executionResult = graphql($schema, $source, '', null, ['name' => 'Han Solo']);

    $expected = new ExecutionResult([
        'greeting' => 'Hello Han Solo.'
    ], []);

    $this->assertEquals($expected, $executionResult);
}

Run that single test case:

./vendor/bin/phpunit --filter testSimpleMutation
HPUnit 7.0.2 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.1.14 with Xdebug 2.6.0
Configuration: /Users/hunguyen/Codes/php/graphql-php/phpunit.xml

.                                                                   1 / 1 (100%)

Time: 184 ms, Memory: 10.00MB

OK (1 test, 1 assertion)

Run the whole functional test

screen shot 2018-03-13 at 4 13 58

screen shot 2018-03-13 at 4 16 08

The weird thing is the error said something about FragTwo which is not include in the test.

array_map(function(\Exception $ex) {
    printf("\n%s", $ex->getMessage());
},$executionResult->getErrors());

I got:

Fragment "FragOne" is never used.
Fragment "FragTwo" is never used

I suspect that there is something is cached inside the validation when run the whole testsuite.

Fix testMaintainsTypeInfoDuringEdit

One test is still failing from VisitorTest. The issue is most likely in the logic how we visit nodes added by visitors. I suspect that we are visited them in the wrong order.

Refactor parser to use the builder pattern

This should be pretty straight-forward because we have ported all the test cases. The idea is to split up the parser into many smaller parsers that each build a specific type of AST.

Remove SchemaInterface

The SchemaInterface is redundant as the schema cannot be replaced in the DI container (this is by design).

Object configuration

We should decide which pattern/solution we want to use for instantiating objects.

The current solution where we use a ConfigTrait is not very intuitive, so we need to come up with a more robust solution for this. This will affect the instantiation of all objects within the library.

Creational Patterns on Wikipedia (yes I know) lists some options that might be worth considering.

Exception handling

We need to think carefully about how we implement exception handling. There are three things to keep in mind:

  • normally, if one field fails to resolve with an exception, the rest of the fields should still resolve and the query should just include errors
  • this means exceptions get swallowed, so applications that report uncaught exceptions (technically these are caught, but only implicitly) need an easy way to access the underlying exceptions after the full query is resolved
  • while developing you may not want GraphQL to swallow exceptions, instead you may want eventual exceptions to remain uncaught so they bubble up to the application's exception handler (which then usually renders it with a stack trace)

Execution

Execution feature check list

  • Fields
  • Arguments
  • Aliases
  • Fragments
  • Operation Name
  • Variables
  • Directives
  • Mutations
  • Inline Fragments

Some thoughts. High-level review step #1.

High level review / preamble

First of all, thanks for working on this. The project looks amazing and I can't wait to work with it in the future. I fully stand behind the reasons for starting a new graphql-php implementation as mentioned in your README. I've dealt with a wide range of issues with both of the alternatives in the past and can fully understand why you started your own implementation. Furthermore, I find the rationale and the resulting architectural decisions outlined in your README very compelling and in-line with what me and my colleague (/cc @pmelab) have discussed in the past. Sadly, we never got around to implement our own library and therefore we are both very happy to see this project grow and shine in the future :).

Let me start with a few observations from working with the past libraries, projected onto my findings in your current code base (so far). High level.

Primitive value tokenization

Very good decision. I wanted to be able to use the C parser for a long time. Enabling this as a feature out of the box is very wise :-). /cc @pmelab

First grade SDL support

This is a very wise decision. In find the SDL to be largely underrated in the broader gql community. I was skeptical at first but fell in love with it and use it exclusively now. It becomes especially powerful with custom directives (which I hope is something you will be implementing too, check out https://dev-blog.apollodata.com/reusable-graphql-schema-directives-131fb3a177d1 for that matter).

I am especially looking forward to your SDL implementation because I want to build the next version of the GraphQL Drupal module around the SDL instead of a custom plugin driven architecture that stitches together the schema automatically which makes our current solution super brittle and not very flexible.

Together with the SDL Directives we would be able to link fields to pieces of configuration for dynamically constructing resolvers at run-time.

From what I can tell, the current implementation requires the SDL or SDL AST as well as a readily built map of resolvers at run-time. For the aforementioned reasons, I would like to be able to, instead of registering a map of resolver functions, register some sort of callable that retrieves the appropriate resolver at run-time on demand. That way I can cache the SDL AST and instead of constructing the whole map of callables at run-time, have it only construct the ones of the fields that are actually part of the query path. This would be in-line with the way the full type objects are built dynamically and on-demand.

First grade support for persistent caching at various levels

One of the most annoying parts of the existing implementations in PHP is the utter lack of considerations for caching strategies. I can see that you've put some thoughts into making your implementation accessible for custom caching implementations by implementing PSR-6. However, it's also important to ensure that each piece is individually serializable which is something both of the other libraries fail to do. That means that query result objects need to be free of any wild references to non-serializable constructs: SDL / Query ASTs (persisted queries) shouldn't contain any closures. Errors need to cleansed of potential stack traces or AST references. Etc.

Caching needs to be possible at all sorts of levels. SDL AST, Query AST (persisted queries), Query Results (including errors!). It should be possible to built caching strategies not only around the whole query, but also parts of the query, contextually. That means it should be possible to hook into the field resolving within the query execution process to fetch parts of a query from cache. The heavy lifting for all of these things should be left to the actual implementation of course.

Considerations for persisted queries

In order to efficiently support persisted queries, it needs to be possible to pre-validate them upon registration and caching their full AST instead of running lexing/parsing and validation for them at run-time. This is important for also benefiting from the possible performance gains of persisted queries vs. just the security / http caching (GET) benefits. This is obviously also part of whatever implementation someone builds around this library, but should be considered in case you plan on building a high-level api for easing custom implementations.

Make the processor accessible for logging and tracking / analytics strategies

Users should be able to easily plug in custom logging and metrics collecting (e.g. newrelic or datadog). I want to be able to analyze individual resolvers and the overall performance of my schema. At a first glance, your architecture looks like it could handle that without having to override a whole bunch of classes because they are tightly coupled. It should stay that way :).

Accompanying projects

Some ideas for accompanying projects that could be built around your base library which, as I understand, will only contain the core engine (good decision!).

  1. Standard HTTP request processing based on PSR-7 (handle the various request formats and extraction of query parameters from GET/POST body).
  2. Batch request support (on top of #1)
  3. File upload support (on top of #1)
  4. Persisted query support with user-specified lookup strategy.
  5. Query analytics
  6. Default server implementation (based on aforementioned and possibly more) stitching together various of these addons.

More soon ...

I need to get back to day work for a bit again now. Will provide more feedback in a bit. I still owe you the code review I promised and I've also got more points I'd like to mention that don't necessarily concern your architecture directly (observations and concerns/ideas from working with the broader graphql ecosystem in the past).

Use Phpstan for static analysis

Pros:

  • It doesn't require any custom PHP extensions like phan does
  • It's faster

Cons:

  • it can be a bit picky
  • it doesn't understand inner functions
  • error suppressing cannot be done with annotations like Phan

Refactor DefinitionBuilder instantiation

Currently, the DefinitionBuilder is instantiated through DI and some of it’s fields are set later through setters. This implementation is quite short-sighted and could be done through a builder (yes I know, builder-builder) much like various contexts are created.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.