Build a REST API
We'll build a small notes API from scratch: list, create, read, update and delete notes. Everything here runs the same on Node and Bun.
1. The server
npm install @server/next// index.js
import server from '@server/next';
export default server()
.get('/', () => 'Notes API');Run it and open http://localhost:3000:
node index.js # or: bun index.js2. List and create
Keep the notes in a Map for now (swap it for a store like Redis to persist them). Return a value from a handler and it is sent as JSON; return a number and it becomes the status code.
import server, { status } from '@server/next';
const notes = new Map();
export default server()
// GET /notes → every note
.get('/notes', () => [...notes.values()])
// POST /notes → create one from the JSON body
.post('/notes', (ctx) => {
const id = crypto.randomUUID();
const note = { id, text: ctx.body.text };
notes.set(id, note);
return status(201).json(note);
});Try it:
curl localhost:3000/notes
curl -X POST localhost:3000/notes -H content-type:application/json -d '{"text":"Buy milk"}'3. Read, update and delete one
Add a route parameter and read it from ctx.url.params. A missing note just returns 404.
// GET /notes/:id
.get('/notes/:id', (ctx) => notes.get(ctx.url.params.id) || 404)
// PUT /notes/:id
.put('/notes/:id', (ctx) => {
const note = notes.get(ctx.url.params.id);
if (!note) return 404;
note.text = ctx.body.text;
return note;
})
// DELETE /notes/:id → 204 No Content
.delete('/notes/:id', (ctx) => {
notes.delete(ctx.url.params.id);
return 204;
});4. Test it
No ports or running server needed. .test() drives requests through the full middleware stack:
// index.test.js
import app from './index.js';
it('creates and reads a note', async () => {
const api = app.test();
const created = await api.post('/notes', { text: 'Hello' });
expect(created.status).toBe(201);
const { id } = await created.json();
const read = await api.get(`/notes/${id}`);
expect(await read.json()).toMatchObject({ text: 'Hello' });
});Next steps
- Persist notes in a store (Redis, the filesystem, and more) instead of a
Map. - Add authentication so each user only sees their own notes.
- Accept file attachments with uploads.