Package: neo4j-graphql-py
neo4j-graphql-pyA GraphQL to Cypher query execution layer for Neo4j and Python GraphQL implementations.Installation and usageInstallpip install neo4j-graphql-pyThen callneo4j_graphql()in your GraphQL resolver. Your GraphQL query will be translated to Cypher and the query passed to Neo4j.fromneo4j_graphql_pyimportneo4j_graphqldefresolve(obj,info,**kwargs):returnneo4j_graphql(obj,info.context,info,**kwargs)resolvers={'Query':{'Movie':resolve}}What isneo4j-graphql-pyA package to make it easier to use GraphQL andNeo4jtogether.neo4j-graphql-pytranslates GraphQL queries to a singleCypherquery, eliminating the need to write queries in GraphQL resolvers and for batching queries. It also exposes the Cypher query language through GraphQL via the@cypherschema directive.How it worksStart with a GraphQL schemaGraphQL First Development is all about starting with a well defined GraphQL schema. Here we'll use the GraphQL schema IDL syntax:type_defs='''directive @cypher(statement: String!) on FIELD_DEFINITIONdirective @relation(name:String!, direction:String!) on FIELD_DEFINITIONtype Movie {movieId: ID!title: Stringyear: Intplot: Stringposter: StringimdbRating: Floatsimilar(first: Int = 3, offset: Int = 0): [Movie] @cypher(statement: "MATCH (this)-[:IN_GENRE]->(:Genre)<-[:IN_GENRE]-(o:Movie) RETURN o")degree: Int @cypher(statement: "RETURN SIZE((this)-->())")actors(first: Int = 3, offset: Int = 0): [Actor] @relation(name: "ACTED_IN", direction:"IN")}type Actor {id: ID!name: Stringmovies: [Movie]}type Query {Movie(id: ID, title: String, year: Int, imdbRating: Float, first: Int, offset: Int): [Movie]}'''We define two types,MovieandActoras well as a top level QueryMoviewhich becomes our entry point. This looks like a standard GraphQL schema, except for the use of two directives@relationand@cypher. In GraphQL directives allow us to annotate fields and provide an extension point for GraphQL.@cypherdirective - maps the specified Cypher query to the value of the field. In the Cypher query,thisis bound to the current object being resolved.@relationdirective - used to indicate relationships in the data model. Thenameargument specifies the relationship type, anddirectionindicates the direction of the relationship ("IN" or "OUT" are valid values)Translate GraphQL To CypherInside each resolver, useneo4j-graphql()to generate the Cypher required to resolve the GraphQL query, passing through the query arguments, context and resolveInfo objects.fromneo4j_graphql_pyimportneo4j_graphqlresolvers={# entry point to GraphQL service'Query':{'Movie':lambdaobj,info,**kwargs:neo4j_graphql(obj,info.context,info,**kwargs)}}GraphQL to Cypher translation works by inspecting the GraphQL schema, the GraphQL query and arguments. For example, this simple GraphQL query{Movie(title:"River Runs Through It, A"){titleyearimdbRating}}is translated into the Cypher queryMATCH(movie:Movie{title:"River Runs Through It, A"})RETURNmovie{.title,.year,.imdbRating}ASmovieSKIP0A slightly more complicated traversal{Movie(title:"River Runs Through It, A"){titleyearimdbRatingactors{name}}}becomesMATCH(movie:Movie{title:"River Runs Through It, A"})RETURNmovie{.title,.year,.imdbRating,actors:[(movie)<-[:ACTED_IN]-(movie_actors:Actor)|movie_actors{.name}]}ASmovieSKIP0@cypherdirectiveNOTE: The@cypherdirective has a dependency on the APOC procedure library, specifically the functionapoc.cypher.runFirstColumnto run sub-queries. If you'd like to make use of the@cypherfeature you'll need to installappropriate version of APOCin Neo4jGraphQL is fairly limited when it comes to expressing complex queries such as filtering, or aggregations. We expose the graph querying language Cypher through GraphQL via the@cypherdirective. Annotate a field in your schema with the@cypherdirective to map the results of that query to the annotated GraphQL field. For example:typeMovie{movieId:ID!title:Stringyear:Intplot:Stringsimilar(first:Int=3,offset:Int=0):[Movie]@cypher(statement:"MATCH (this)-[:IN_GENRE]->(:Genre)<-[:IN_GENRE]-(o:Movie) RETURN o ORDER BY COUNT(*) DESC")}The fieldsimilarwill be resolved using the Cypher queryMATCH(this)-[:IN_GENRE]->(:Genre)<-[:IN_GENRE]-(o:Movie)RETURNoORDERBYCOUNT(*)DESCto find movies with overlapping Genres.Querying a GraphQL field marked with a@cypherdirective executes that query as a subquery:GraphQL:{Movie(title:"River Runs Through It, A"){titleyearimdbRatingactors{name}similar(first:3){title}}}Cypher:MATCH(movie:Movie{title:"River Runs Through It, A"})RETURNmovie{.title,.year,.imdbRating,actors:[(movie)<-[:ACTED_IN]-(movie_actors:Actor)|movie_actors{.name}],similar:[xINapoc.cypher.runFirstColumn("WITH {this} AS thisMATCH (this)-[:IN_GENRE]->(:Genre)<-[:IN_GENRE]-(o:Movie)RETURN o",{this:movie},true)|x{.title}][..3]}ASmovieSKIP0Query Neo4jInject a Neo4j driver instance in the context of each GraphQL request andneo4j-graphql-pywill query the Neo4j database and return the results to resolve the GraphQL query.fromneo4j_graphql_pyimportmake_executable_schemaschema=make_executable_schema(type_defs,resolvers)importneo4jdefcontext(request):globaldriverifdriverisNone:driver=neo4j.GraphDatabase.driver("bolt://localhost:7687",auth=("neo4j","neo4j"))return{'driver':driver,'request':request}fromariadne.asgiimportGraphQLimportuvicornrootValue={}app=GraphQL(schema=schema,root_value=rootValue,context_value=context,debug=True)uvicorn.run(app)See/examplesfor complete examples using different GraphQL server libraries.BenefitsSend a single query to the databaseNo need to write queries for each resolverExposes the power of the Cypher query language through GraphQLExamplesSee/examplesfor complete examples using different GraphQL server libraries.