Javascript Code Demo using Express
All of the code shown is available as a simple Node.js application using Express. This application uses a ready-to-use demo database with the goodreads dataset containing Book and Author entities.

Setup
Install the Neo4j driver and Express:
npm init -y
npm install neo4j-driver expressCode language: Shell Session (shell)
Connect to the database
Since this sample uses a public database, it will connect without any changes.
Main application – app.js
const express = require('express');
const neo4j = require('neo4j-driver');
const app = express();
const PORT = 3000;
// Neo4j connection
// Create a driver instance to manage the connection to Neo4j
// The 'neo4j+s' protocol uses encrypted connections
const driver = neo4j.driver(
'neo4j+s://demo.neo4jlabs.com',
neo4j.auth.basic('goodreads', 'goodreads')
);
// GET /books - Get featured books from diverse authors
app.get('/books', async (req, res) => {
// Create a new session for this request
// Sessions are lightweight and should be created per request
const session = driver.session();
try {
// Execute a Cypher query to find books by specific authors
// The MATCH clause finds Book nodes connected to Author nodes
// The WHERE clause filters for specific author names
// COLLECT aggregates multiple authors into an array
const result = await session.run(
`MATCH (book:Book)<-[:AUTHORED]-(author:Author)
WHERE author.name IN ['Chimamanda Ngozi Adichie', 'James Baldwin',
'Toni Morrison', 'Maya Angelou', 'Gabriel García Márquez']
RETURN book.title AS title, collect(author.name) AS authors
LIMIT 10`
);
// Transform Neo4j records into JSON objects
// record.get() extracts values by their alias from the RETURN clause
const books = result.records.map(record => ({
title: record.get('title'),
authors: record.get('authors')
}));
res.json(books);
} catch (error) {
res.status(500).json({ error: error.message });
} finally {
// Always close the session to release resources
await session.close();
}
});
// GET /books/:title - Get book by title
app.get('/books/:title', async (req, res) => {
const session = driver.session();
try {
// Use parameterized queries to prevent Cypher injection
// The $title parameter is safely substituted by the driver
// OPTIONAL MATCH ensures we get the book even if it has no authors
const result = await session.run(
`MATCH (book:Book {title: $title})
OPTIONAL MATCH (book)<-[:AUTHORED]-(author:Author)
RETURN book.title AS title, book.isbn AS isbn,
collect(author.name) AS authors`,
{ title: req.params.title } // Parameters passed as second argument
);
// Check if any records were returned
if (result.records.length === 0) {
return res.status(404).json({ error: 'Book not found' });
}
// Extract data from the first (and only) record
const record = result.records[0];
res.json({
title: record.get('title'),
isbn: record.get('isbn'),
authors: record.get('authors')
});
} catch (error) {
res.status(500).json({ error: error.message });
} finally {
await session.close();
}
});
// GET /books/author/:name - Get books by author
app.get('/books/author/:name', async (req, res) => {
const session = driver.session();
try {
// Find all books written by a specific author
// The arrow in -[:AUTHORED]-> shows the relationship direction
// (author)-[:AUTHORED]->(book) means author wrote the book
const result = await session.run(
`MATCH (author:Author {name: $name})-[:AUTHORED]->(book:Book)
RETURN book.title AS title, book.isbn AS isbn
LIMIT 10`,
{ name: req.params.name }
);
// Map each record to a simplified book object
const books = result.records.map(record => ({
title: record.get('title'),
isbn: record.get('isbn')
}));
res.json(books);
} catch (error) {
res.status(500).json({ error: error.message });
} finally {
await session.close();
}
});
// Start the Express server
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log('\nTry these endpoints:');
console.log(' http://localhost:3000/books');
console.log(' http://localhost:3000/books/Americanah');
console.log(' http://localhost:3000/books/author/Chimamanda%20Ngozi%20Adichie');
console.log(' http://localhost:3000/books/author/James%20Baldwin');
});
// Cleanup on exit
// Gracefully close the driver connection when the process terminates
process.on('SIGINT', async () => {
await driver.close();
process.exit();
});Code language: JavaScript (javascript)
The Express framework simplifies routing with clean endpoint definitions. Each endpoint creates a session, runs a Cypher query, and returns JSON results. The queries specifically highlight diverse authors like Chimamanda Ngozi Adichie, James Baldwin, Toni Morrison, and Maya Angelou.
Key Concepts Explained
Driver and Sessions
- Driver: A long-lived object that manages the connection pool to Neo4j. Create once per application.
- Session: A short-lived object for executing queries. Create one per request/transaction.
- Always close sessions in a finally block to prevent connection leaks.
Cypher Query Patterns
- MATCH: Finds patterns in the graph
- OPTIONAL MATCH: Like MATCH but returns null if pattern doesn’t exist (similar to LEFT JOIN)
- WHERE: Filters results based on conditions
- RETURN: Specifies what data to return
- COLLECT: Aggregates values into a list
Parameterized Queries
Always use parameters (like $title, $name) instead of string concatenation to prevent Cypher injection attacks:
// Good - Safe from injection
session.run('MATCH (n:Node {name: $name})', { name: userInput })
// Bad - Vulnerable to injection
session.run(`MATCH (n:Node {name: '${userInput}'})`)Code language: JavaScript (javascript)
Error Handling
The try-catch-finally pattern ensures:
- Errors are caught and returned as HTTP error responses
- Sessions are always closed, even if errors occur
- Resources are properly released
Run and test the application
Run the server:
node app.jsCode language: Shell Session (shell)
Test the endpoints:
# Get featured books from diverse authors
curl http://localhost:3000/books
# Get a specific book
curl http://localhost:3000/books/Americanah
curl "http://localhost:3000/books/Half%20of%20a%20Yellow%20Sun"
# Get books by Chimamanda Ngozi Adichie
curl "http://localhost:3000/books/author/Chimamanda%20Ngozi%20Adichie"
# Get books by James Baldwin
curl "http://localhost:3000/books/author/James%20Baldwin"
# Get books by Toni Morrison
curl "http://localhost:3000/books/author/Toni%20Morrison"Code language: Shell Session (shell)
Or using HTTPie:
http :3000/books
http ":3000/books/Americanah"
http ":3000/books/author/Chimamanda Ngozi Adichie"
http ":3000/books/author/James Baldwin"Code language: Shell Session (shell)
Sample Response
// GET /books
[
{
"title": "Americanah",
"authors": ["Chimamanda Ngozi Adichie"]
},
{
"title": "Half of a Yellow Sun",
"authors": ["Chimamanda Ngozi Adichie"]
},
{
"title": "The Fire Next Time",
"authors": ["James Baldwin"]
}
]
// GET /books/author/Chimamanda%20Ngozi%20Adichie
[
{
"title": "Americanah",
"isbn": "0307455920"
},
{
"title": "Half of a Yellow Sun",
"isbn": "1400044162"
},
{
"title": "Purple Hibiscus",
"isbn": "1616202416"
}
]Code language: JavaScript (javascript)
Resources
- Documentation:Neo4j JavaScript Driver
- Documentation:Express.js


