Node.js Project: Notes API
This Node.js project combines everything from the tutorial into one small but realistic app: a notes REST API built with Express that saves notes to a JSON file. It uses ES modules, fs/promises, path, middleware, environment variables and centralized error handling.
Project Setup
mkdir notes-api && cd notes-api
npm init -y
npm pkg set type=module
npm install express
echo PORT=4000 > .env
npm pkg set scripts.dev="node --env-file=.env --watch server.js"added 64 packages in 3s
The Storage Module
// store.js
import { readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { randomUUID } from 'node:crypto';
const FILE = path.join(import.meta.dirname, 'notes.json');
async function load() {
try {
return JSON.parse(await readFile(FILE, 'utf8'));
} catch (err) {
if (err.code === 'ENOENT') return [];
throw err;
}
}
const save = (notes) => writeFile(FILE, JSON.stringify(notes, null, 2));
export async function list() { return load(); }
export async function create(text) {
const notes = await load();
const note = { id: randomUUID(), text, createdAt: new Date().toISOString() };
notes.push(note);
await save(notes);
return note;
}
export async function remove(id) {
const notes = await load();
const rest = notes.filter((n) => n.id !== id);
await save(rest);
return rest.length !== notes.length;
}(module exports list, create and remove)
The Server
// server.js
import express from 'express';
import * as store from './store.js';
const app = express();
app.use(express.json());
app.get('/api/notes', async (req, res, next) => {
try { res.json(await store.list()); } catch (e) { next(e); }
});
app.post('/api/notes', async (req, res, next) => {
try {
const text = req.body.text?.trim();
if (!text) return res.status(400).json({ error: 'text is required' });
res.status(201).json(await store.create(text));
} catch (e) { next(e); }
});
app.delete('/api/notes/:id', async (req, res, next) => {
try {
const ok = await store.remove(req.params.id);
ok ? res.status(204).end() : res.status(404).json({ error: 'Note not found' });
} catch (e) { next(e); }
});
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Server error' });
});
const port = Number(process.env.PORT ?? 3000);
app.listen(port, () => console.log(`Notes API on http://localhost:${port}`));$ npm run dev
Notes API on http://localhost:4000
POST /api/notes {"text":"Learn streams"}
{"id":"5f0c...","text":"Learn streams","createdAt":"2026-10-31T10:00:00.000Z"}How It Works
- store.js hides the file storage, so you could swap it for a database later without touching routes.
- The try/catch + next(e) pattern sends unexpected errors to one handler (works in Express 4 and 5).
- randomUUID gives each note a unique id without any extra package.
- The port comes from .env, loaded by --env-file.
Exercises
- Add PUT /api/notes/:id to edit a note's text.
- Support ?search=word to filter notes by text.
- Add an API-key middleware that protects POST and DELETE.
- Replace the JSON file with SQLite or MongoDB.
- Build a React front end that lists, adds and deletes notes using fetch.
Frequently asked questions
What are good Node.js projects for beginners?
A notes or todo REST API, a URL shortener, a CLI that renames files, a weather API proxy, and a real-time chat with WebSockets are popular beginner projects.
Can I use a JSON file as a database in Node.js?
For learning and tiny tools, yes. It does not handle many simultaneous writes safely, so real apps should use a database such as SQLite, PostgreSQL or MongoDB.
How do I deploy a Node.js API?
Push your code to Git and deploy to a platform like Render, Railway or Fly.io, or a VPS running Node behind Nginx with pm2. Set environment variables in the host's settings.