neo4j-graphql-js
neo4j-graphql-js copied to clipboard
Add Schema Stitching Example
This creates an example repository in /examples
to showcase how the freshly renovated graphql schema stitching API can be leveraged for neo4j-graphql-js
.
When I was working on Oclelot-Social (formerly known as Human Connection) I made first-had experience of the advantages and disadvantages of neo4j-graphql-js
.
Our biggest pain point with neo4j-graphql-js
was the difficulty to customize the schema and write our own custom code aside of CRUD operations. I wished GraphQL Stitching had existed back then, because it's solving that problem beautifully.
No more custom fallback type resolvers
Use case: You mix your own mutation/query resolvers with those of neo4j-graphql-js
. Unfortunately, you bypass neoj4-graphql-js
then. If your custom resolver returns a type defined also your neo4j-graphqj-js
schema, good luck writing all the code to fetch the associated data. We wrote our own "fallback resolvers" which checked if a parent.field
was already set (then it's most likely populated by neo4j-graphql-js
) and otherwise make another database call to fetch it.
Solution with grapqhl schema stitching: Write your own custom stuff and then call delegateToSchema
with a query operation on the type you want to return. :tada:
No more man-in-the-middle attacks on resolveInfo
Use-case: Your custom resolvers need data which may not be requested by the client. We "hacked" the resolveInfo
object to request certain fields (e.g. id
, createdAt
or disabled
) even if they weren't requested by the client. We would pass this manipulated resolveInfo
to neo4j-graphql-js
. That way we could make neo4j-graphql-js
return all properties of the nodes which we needed.
Solution with grapqhl schema stitching: You specify selectionSet
in your resolver. :tada:
Implement performant orderBy of aggregated data
We ran into performance issues while ordering by fields that have a @cypher
directive. You could even use Schema Stitching as a workaround. First, you write a custom database query which is known to perform well and populates a list of id
s. Then you delegateToSchema
the ids to neo4j-graphql-js
. If the results are not in order, you could still reorder the results based on the order of your pre-populated ids, e.g. just before you return
in your custom resolver.
TODO
- [ ] Introduce lerna.js, so we share a common
node_modules
folder - [ ] Add the example tests to the build pipeline
- [ ] Make top-level queries and resolvers exposed by
neo4j-graphql-js
inaccessible to the client (e.g. because of authorization)
Hi @roschaefer, thanks for an example using schema stitching, I am curious, how you will compare this with the apollo federation approach? Thanks
Looks like there are a few files too many in the root directory.
/package-lock.json
/package.json
/yarn.lock
Don't forget to remove them.
Looks like there are a few files too many in the root directory.
/package-lock.json /package.json /yarn.lock
Don't forget to remove them.
Thanks a million!
Hi @roschaefer, thanks for an example using schema stitching, I am curious, how you will compare this with the apollo federation approach? Thanks
The crucial difference is that in GraphQL schema stitching, the subschemas don't know each other. They are autonomous. See this blog post: https://product.voxmedia.com/2020/11/2/21494865/to-federate-or-stitch-a-graphql-gateway-revisited
I must admit, I haven't used Apollo Federation myself in production. My goal in another project was that I used a remote GraphQL schema at https://graphcms.com/. Their schema would do a lot, but I wanted to implement my own authentication/authorization, data validation and custom logic. It didn't seem possible with Apollo Federation because I have no control over the schema at GraphCMS. However, with GraphQL schema stitching, this is possible and works beautifully. My architecture looks like this:
(Client)--[:PUBLIC_ACCESS]-->(CustomBackend)--[:API_KEY_PROTECTED_ACCESS]-->(GraphCMS)
Now, after I accomplished that, the idea came to my mind to use the same technique for neo4j-graphql-js
knowing that the output there is an executableSchema
. And it works! Since it's running in the same NodeJS process it's not even a performance overhead.
I think the main advantage of this strategy is that it defeats the tight coupling between type-defintions and resolvers. This is by design since neo4j-graphql-js
is like Type-Definition-Driven-Development. Nevertheless, according to my own experiences from production, this is not desirable for the use-case of running a publicly accessible fullstack application on top of neo4j-graphql-js
and Neo4J
.
But doing it this way, I have all the freedom I want regarding my custom type definitions and still get all the convenience which neo4j-graphql-js
brings.
Does that make sense @XBeg9 ?
Looks like there are still 3 empty files in root which don't belong there. Maybe its a GitHub issue showing these or I am misinterpreting these?
Also a small typo for the folder example/schema-stitching/src/db/entitites/
and its references ("entities" would be correct).
I like the example!
Looks like there are still 3 empty files in root which don't belong there. Maybe its a GitHub issue showing these or I am misinterpreting these? Also a small typo for the folder
example/schema-stitching/src/db/entitites/
and its references ("entities" would be correct).I like the example!
Thanks, typo is fixed now. This PR waits for #549 to be merged, that's why you see those three files in the PR. It's just UNIX file permissions, no changes to the content.
https://github.com/neo4j-graphql/neo4j-graphql-js/issues/608