This example project shows how to combine Spring GraphQL 1.2.0 with Spring Data Neo4j 7.1.0. The project itself is based on Spring Boot 3.1 to make use of some very nice improvements.
-
Support for Scroll/Pagination https://docs.spring.io/spring-graphql/docs/current/reference/html/#data.pagination.scroll
-
Need to implement some functionality in Spring Data Neo4j first
-
-
Native image support without additional definitions
-
Spring Data Neo4j misses some hints to compile out-of-the-box with Spring GraphQL
-
-
@ServiceConnection
: https://docs.spring.io/spring-boot/docs/3.1.x/reference/htmlsingle/#features.testing.testcontainers.service-connections -
Testcontainers at development time: https://docs.spring.io/spring-boot/docs/3.1.x/reference/htmlsingle/#features.testing.testcontainers.at-development-time
-
@ImportTestcontainers
: https://docs.spring.io/spring-boot/docs/3.1.x/reference/htmlsingle/#features.testing.testcontainers.at-development-time.importing-container-declarations
Starting the application from the tests or running integration tests, the project will use Neo4j-Migrations to create the initial dataset.
Although the current version of the Neo4j Java driver is 5.7.,
the Spring Boot autoconfiguration is backwards compatible to the whole 4.x versions.
As a consequence, it cannot configure the metrics provider automatically and we need to provide a ConfigBuilderCustomizer
to set Micrometer
as the adapter.
@Bean
ConfigBuilderCustomizer configBuilderCustomizer() {
return configBuilder -> configBuilder.withMetricsAdapter(MetricsAdapter.MICROMETER);
}
This will provide following metrics to consume. Accessible via http://localhost:8080/actuator/metrics/<neo4j.driver.metric>;
neo4j.driver.connections.acquiring
neo4j.driver.connections.acquisition
neo4j.driver.connections.acquisition.timeout
neo4j.driver.connections.closed
neo4j.driver.connections.creating
neo4j.driver.connections.creation
neo4j.driver.connections.failed
neo4j.driver.connections.idle
neo4j.driver.connections.in.use
neo4j.driver.connections.usage
The health endpoint is enriched with the information about the connection to the running Neo4j instance and can be queried at http://localhost:8080/actuator/health/neo4j.
Please be aware that both, metrics and health endpoints, are configured without any security mechanisms in this project’s configuration. Always check the information you are exposing before deploying an application to the public.
The project provides a Neo4j testcontainer instance if it gets started from the tests. (Docker needed)
./mvnw spring-boot:test-run
If you want to connect to a running instance, you have to start the application with the matching environment variables
SPRING_NEO4J_AUTHENTICATION_PASSWORD=<your password> \\
SPRING_NEO4j_URI=<your uri, default bolt://localhost:7687> \\
./mvnw spring-boot:run
Please keep in mind that the application is focused on using the movie dataset.
If not happen yet, please run the :play movies
guide and the Cypher query to populate the database.
This requires you to have GraalVM (Java 17 based) installed and included your $PATH on your machine. There is a pre-configured profile (native) that will invoke the GraalVM’s native maven plugin.
./mvnw -Pnative clean package
After it has successfully compiled, you can invoke the executable similar to the command above.
SPRING_NEO4J_AUTHENTICATION_PASSWORD=<your password> \\
SPRING_NEO4j_URI=<your uri, default bolt://localhost:7687> \\
target/spring-neo4j-graphql
The current schema looks like this:
type Query {
movies : [Movie]
movie(title : String!) : Movie
}
type Movie {
id: ID!
title: String!
description : String!
"Random number 0 - 100 as an example for aggregation of data"
rating: Int
actors: [Person]
directors: [Person]
}
"A person is either an actor or a director"
type Person {
id: ID!
name: String!
yearOfBirth: Int
}
Example queries as you can see above are:
{movies {title, actors {name, yearOfBirth}}}
will return:
{
"data": {
"movies": [
{
"title": "The Matrix",
"actors": [
{
"name": "Gloria Foster",
"yearOfBirth": null
},
{
"name": "Hugo Weaving",
"yearOfBirth": 1960
},
{
"name": "Keanu Reeves",
"yearOfBirth": 1964
},
{
"name": "Emil Eifrem",
"yearOfBirth": 1978
}, ...
]},
{
"title": "The Matrix Reloaded",
"actors": [
{
"name": "Gloria Foster",
"yearOfBirth": null
}, ....
]}
]}
}
{movie (title: "The Matrix") {title, description}}
will return:
{
"data": {
"movie": {
"title": "The Matrix",
"description": "Welcome to the Real World"
}
}
}
It is possible to aggregate the data from different sources.
For example the rating
field of the Movie
will be a random generated number between 0 and 100.
{movie (title: "The Matrix") {title, rating}}
returns
{
"data": {
"movie": {
"title": "The Matrix",
"rating": 99
}
}
}