Add a new fully functional example to the docs
I was studying from the liftoff series in this course for the second time as I needed graphql in a project (I started this course a year ago when I wanted to learn more about graphql in general).
I link their incremental approach of teaching one thing at a time along with the companion illustrations with each lesson. They use Apollo client and server packages in the course (surely since these are their products), but because I needed to use php in the first place, I had to follow along and incrementally write equivalent code in php.
I thought about sharing the code in php so that any learner coming from their course would have the equivalent code in php in hand, thus making the migration process even easier.
If you agree, I can either:
- Add the link of the repo to the docs
- If you want full control over the code, I can clone this package(webonyx/graphql-php) and add the code to it(a bit cumbersome, but doable)
I don't mind adding a link to your example in the docs. A couple of notes:
- How do we know it is working? There are no tests?
- What is the reason for separating
appandsrc? What goes where? - Should
GraphQLControllerfollow PSR-4?
Thanks for choosing the easier option. Regarding your notes :
-
The tests: 1.1 Do you mean some tests like the ones present in StarWarsQueryTest.php and GraphQLTest.php ?
1.2 As a follow up to the previous point, Is it mandatory to use
PHPUnitor can I usePestif I would write some tests? -
I think that I used
src/Controllerwith no specific reason in mind. Regardingapp/I just followed laravel's style. I may refactor the code to:2.1 adhere more to laravel style by changing
src/Controllertoapp/http/Controllers2.2 follow what you would suggest about directory structure changes -
I usually tend to prefer to follow PSR-4, but I still don't fully understand your question:
3.1 Do you mean that it is not necessary to follow PSR-4 in the example? OR 3.2 Is there something I am doing wrong that makes
GraphQLControllernot follow PSR-4 even though I am intending to do so?
If the tests point is confirmed, I may take some time to understand the pattern used in this package then I would write the tests. So the PR may take some time, but I will follow the guidance present in your next response.
So I checked the aforementioned tests, and after looking into them carefully, it seems that they are testing the library itself to make sure that it works as expected.
I thought about writing tests about the structure of the data I am expecting to receive from the endpoint, but definitely I will get the structure I want since I am using graphql :).
I would be grateful if you provide me with an example that aligns with the package requirements so that I can have a blueprint for writing tests.
- Yeah, some integration tests to show that the resolvers are working as intended would be great. There can still be mistakes, such as typos in field names, mismatches in data types, etc. Pest is fine with me.
- I would favor the integration of
srcintoappas you suggested. GraphQLControllerdefines more than one class in one file. I have always just done one class per file, although I am not sure if that is a strict requirement for PSR-0/PSR-4.
Okay.
- The tests would take some time, but now I get an idea of what I need to do.
- That's great
- Regarding psr-4, yeah if there is more than 1 class in a file, then the autoloading functionality will only work for the class that has a name exactly as the filename, and the rest of the classes within a file won't be autoloaded and then we would need to manually require the file
I didn't catch that point before because the other classes within GraphqQLController.php file was intended to be used only within that file. I wanted to move them in a dedicated types directory like the blog example in the docs, but I thought this would add some complexity to the code.
But now I see the importance of separation of concerns, so I will make the mentioned refactorings and come later with the latest updates.
It has been a while, but I am back.
Some changes that have been made (I have a dedicated branch for each change in the repo):
- Moved ObjectTypes to a dedicated
typesdirectory and a file for each type - Created
TypeRegistrythat is similar to theBlogexample since I encountered this error
Schema must contain unique named types but contains multiple types named "Track"
- Add tests for the resolvers
Finally, I have got a question about the previous changes:
Before using a TypeRegistry, I used to instantiate a new object from each ObjectType like so
// config to be provided to the constructor of the ObjectType class
'type' = new TrackType()
On testing the endpoint with postman, I have never had any issues.
But when I started writing some tests, I encountered this error
Schema must contain unique named types but contains multiple types named "Track"
although that I had just 1 test back then so there were no shared context between the tests.
I asked chatGPT about that, and I got a generated answer that I wasn’t fully convinced by it, so I thought about asking for an explanation here to both understand and document the journey.
The generated answer:
🤔 So Why Doesn’t the Error Happen in Postman (via GraphQLController)?
Because in GraphQLController.php, you only instantiate the types once per request.
In a normal PHP request (e.g. through Postman), PHP runs GraphQLController::handle() once, then the script finishes. Even if you create new TrackType() multiple times, those instances live only during that single execution context. So Webonyx sees it as one schema being built from scratch, with no conflict.
✅ No duplicate type registration in memory
new TrackType() // used 3x in one request, but not kept alive
💡 So Webonyx doesn’t complain, because the type registry is empty at the beginning and gets discarded after the request.
❌ But in Tests...
Pest (or PHPUnit) runs multiple test cases in one process, or at least reuses the same runtime within a file. That means:
-
If your schema includes:
new TrackType(), new TrackType(), new TrackType() -
Then Webonyx internally sees 3 different objects with the same name: "Track".
-
And its TypeRegistry throws:
Schema must contain unique named types but contains multiple types named "Track"
🧠 Analogy
| Environment | Instantiation Scope | Type Registry Conflict? |
|---|---|---|
| Postman request | Single script run | ❌ No, memory clears per request |
| Pest test suite | Persistent test runtime | ✅ Yes, registry holds duplicate "Track" types |
✅ Conclusion & Action
Even if your schema works fine in a controller, once you move to tests (or caching in prod), you must instantiate each named type exactly once per schema build.
This is by design in Webonyx (and GraphQL spec in general): type names must be unique.
End of the generated answer
To confirm his answer, I found this issue.
And also in the blog example, the type registry approach is used.
But I am not convinced with the answer explaining not getting errors on testing the api using postman. Is the generated answer really correct?
Using a TypeRegistry makes sense, especially for an example like yours that should be at least somewhat complete and production ready-ish.
I see your point, I just wondered why I didn't get any errors using the pre-TypeRegistry approach on using postman :) Anyway, what other modifications may I add to the repo so that it is ready to be added to the docs?
If I would create a PR, what about creating another example in the examples directory and add in it a readme file that points to the repo?
@spawnia Any updates?