-
Notifications
You must be signed in to change notification settings - Fork 154
Suggestion: User-driven mutations with neo4j-graphql selection resolution #215
Comments
Since this didn't generate much talk, I started reading the source to determine how hard it would be to fork this repo and add the features I wanted. And, hey, it turns out there's an undocumented feature of adding a Update: it worked beautifully! I just added a |
I read over the docs again and realized there's a whole API spec I didn't even see before which covers most of these topics. I'll go ahead and close this. |
lucky this post is pretty recent. Thanks to @a-type . I was trying to do a simple create and got this same error. Can you please post a sample of your schema and resolver for reference. I think I am missing something. |
@aonamrata here's how I would modify my original example: const typeDefs = `
type Mutation {
createPost(input: PostCreateInput!): Post!
@cypher(
"""
MATCH (user:User {id:$cypherParams.userId})
CREATE (post:Post)<-[:AUTHOR_OF]-(user)
SET post += $input
RETURN post
"""
)
}
`
const resolvers = {
Mutation: {
createPost: neo4jgraphql
}
};
// to create my context for my GraphQL server:
const createContext = async (req) => {
// this logic you will need to implement yourself - you just need to know the
// authenticated user for this request, which may be stored in a token or header
const user = await getUser(req);
return {
driver, // neo4j driver
// all fields in this object will be included in @cypher directives
cypherParams: {
userId: user && user.id
}
};
}; Note the use of |
For generating unique IDs for created resources, I also created a directive |
I'm getting the same error in a slightly different scenario. I want to reuse a mutation that I've created using the cypher directive from another mutation: Using neo4j-graphql-js version 2.16.1. 🤔 |
@a-type a slightly better approach is to use Also, it would be great to have a few examples of creating custom directives that change the cypher query accordingly to our needs (for example: link the logged user).
|
Context: I've been developing an app with an Apollo server for the past year using plain old
neo4j-driver
and I was getting tired of the verbosity and worried about all the extra database queries, so I thought I'd come back to this project and see how it's doing. After integrating it, I'm super impressed with the query experience! But the mutations miss my use case completely.My use case
Building out my GraphQL app from scratch without relying on generated code has left me with a less CRUD-style schema, which I think has some great benefits.
For instance, let's consider the authorization around allowing a user to create a new post. If I take a naive / generated CRUD approach, I've got to figure out how to properly authorize both the
CreatePost
andAddUserPost
mutations to create my post and attach it to the user, respectively. Do I really want to allow the client app to create arbitrary relationships between Users and Posts? Obviously they should only be allowed to create posts attached to their own User. Now I have to add some kind of directive or middleware logic to enforce that.However, if I'm less constrained by CRUD semantics, I can just create a mutation like this:
I don't even have to write authorization logic in this scenario. The user can only create posts attached to their own identity, which is securely verified by their authentication token. After all I'm writing a client API, not an ORM; I don't need things to be 100% CRUD, I am trying to enable behaviors for users. On top of that, I just have one mutation for the client, not two; my backend technology decisions are not leaking into my API surface area and ruining my semantics.
Where this library comes in
Now, obviously I could just write those kinds of mutations and use
neo4j-graphql-js
for my read operations--and in fact that's what I do right now. But GraphQL doesn't make distinctions between read and write exclusively. When I run a mutation, my client will often request a selection set which includes deeply nested data which was not involved in the mutation itself. That's whereneo4j-graphql-js
really shines; the ability to convert those complex selection sets into Cypher queries automatically.What I'd like to see is a way to enable a user to write their own mutation, Cypher and all, to do exactly what they want-- and then delegate to the Cypher conversion layer of
neo4j-graphql-js
to fulfill the selection set requested by the client as either another query clause, or a second query entirely.I already tried to hack this together using the library as it is today:
... but the library complained:
at which point I briefly considered manually modifying my
info
parameter to change the selection operation type to query and try to trickneo4jgraphql
, but then decided it might be more productive to tell y'all about my use case and start some discussion on the topic.Closing thoughts
I'll say it again, I really love the usage of this library for query operations. There's so much value just in the conversion layer between GraphQL and Cypher. Enabling more use cases may be as simple as decoupling that layer from the rest of the library so it can be reused in more situations. But, as it stands, the mutations fall short for me. It seems like my use case (serving a GraphQL client API to an app) is not really the prime target here, for sure. Maybe I'm missing the point of the library completely - do let me know if so. But it's just so close to working for me, I thought I would at least present my case here.
The text was updated successfully, but these errors were encountered: