digiaonline / graphql-php Goto Github PK
View Code? Open in Web Editor NEWA PHP7 implementation of the GraphQL specification.
Home Page: https://facebook.github.io/graphql/
License: MIT License
A PHP7 implementation of the GraphQL specification.
Home Page: https://facebook.github.io/graphql/
License: MIT License
We need to add support for validation using the Visitor pattern.
The following rules have been implemented:
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:
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.
The last test case for the OverlappingFieldsCanBeMerged validation rule finds three conflicts when it should only find one, this is a bug that should be fixed later.
@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.
Currently, Scrutinizer finds 194 potential issues with this project:
https://scrutinizer-ci.com/g/digiaonline/graphql-php/issues/master
We should go through all of these and fix any potential bugs.
We need to port the test cases from the reference implementation found here:
https://github.com/graphql/graphql-js/blob/master/src/language/__tests__/blockStringValue-test.js
You can look at our other test cases if you want to see an example.
We need to port the Star Wars end-to-end tests from the reference implementation to get a better idea of how combat-ready this library is. https://github.com/graphql/graphql-js/tree/master/src/__tests__
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:
Is this project ready for heavy production loads by teams outside of yourselves?
Is there a migration path from Youshido to this one?
What kind of stability/support would another team be able to expect from this package?
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?
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.
Add contributing guidelines and GitHub templates.
: void
etc. so composer.json is wrongWe need to add basic support for introspection queries.
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).
There's one incomplete test case that is failing
We need to port the test cases from the reference implementation found here:
https://github.com/graphql/graphql-js/blob/master/src/language/__tests__/lexer-test.js
You can look at our other test cases if you want to see an example.
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.
We need to port the test cases for the DefinitionPrinter
class. The reference implementation can be found here: https://github.com/graphql/graphql-js/blob/master/src/utilities/__tests__/schemaPrinter-test.js
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);
}
./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)
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.
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.
For custom scalar type e.g: DateTime
We need to implement the support for giving a Resolver map to the SchemaBuilder
to wire up schemas that are defined using SDL. Apollo's GraphQL Tools uses a similar approach (https://www.apollographql.com/docs/graphql-tools/resolvers.html#Resolver-map). However, we should implement this using classes instead of closures.
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.
We could take a similar approach as the GraphQL Java lib has, which is documented here:
http://graphql-java.readthedocs.io/en/v7/schema.html
Original from graphql/graphql-spec#252
We need support building build a schema from Schema Definition Language (SDL).
The SchemaInterface
is redundant as the schema cannot be replaced in the DI container (this is by design).
Especially in type-hints so we don't accidentally get a TypeError
We need to add support for extending schemas. The reference implementation can be found here:
https://github.com/graphql/graphql-js/blob/master/src/utilities/extendSchema.js
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.
We need to think carefully about how we implement exception handling. There are three things to keep in mind:
errors
Execution feature check list
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.
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
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.
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.
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.
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 :).
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!).
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).
We need to implement support for converting AST trees into GraphQL strings in order to implement #11. We have already implemented all of the nodes so this should be fairly straightforward.
The reference implementation can be found here:
https://github.com/graphql/graphql-js/blob/master/src/language/printer.js
We should try to find a more clean solution for instantiating types in e.g. definition.php.
Pros:
Cons:
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.