Express.js Snippets
About Express.js
Express helps you build web APIs quickly. This learning track uses modular layers, request validation, error handling, and a mini project-ready API pattern.
Project Structure for Express API Learning
Layer your API from route to controller to service to keep endpoints easy to test and extend.
bookmarks-api/
src/
app.js
server.js
routes/bookmarkRoutes.js
controllers/bookmarkController.js
services/bookmarkService.js
middleware/errorHandler.js
middleware/validate.js
middleware/apiKeyAuth.js
schemas/bookmarkSchemas.js
tests/
bookmarks.test.js
package.jsonInstall Dependencies
Install Express and common API helpers for logging, CORS, environment config, and schema validation.
npm init -y
npm install express cors morgan dotenv zod
npm install -D supertestBootstrap App with Middlewares (src/app.js)
Register middleware once in app.js, then keep server startup in a separate file.
import express from 'express'
import cors from 'cors'
import morgan from 'morgan'
import bookmarkRoutes from './routes/bookmarkRoutes.js'
import { errorHandler } from './middleware/errorHandler.js'
const app = express()
app.use(cors())
app.use(express.json())
app.use(morgan('dev'))
app.get('/health', (_req, res) => res.json({ ok: true }))
app.use('/api/bookmarks', bookmarkRoutes)
app.use(errorHandler)
export default appZod Validation Middleware (src/middleware/validate.js)
Validate input at route boundaries and fail fast with useful errors.
export function validate(schema) {
return (req, _res, next) => {
const result = schema.safeParse(req.body)
if (!result.success) {
return next({ status: 400, message: result.error.issues[0].message })
}
req.body = result.data
next()
}
}Bookmark Schema and Routes (src/routes/bookmarkRoutes.js)
Pair input schemas with route declarations for predictable endpoint behavior.
import { Router } from 'express'
import * as controller from '../controllers/bookmarkController.js'
import { validate } from '../middleware/validate.js'
import { createBookmarkSchema } from '../schemas/bookmarkSchemas.js'
const router = Router()
router.get('/', controller.listBookmarks)
router.post('/', validate(createBookmarkSchema), controller.createBookmark)
export default routerController + Service Pattern
Controllers stay HTTP-focused while services contain business rules.
// src/controllers/bookmarkController.js
import * as service from '../services/bookmarkService.js'
export async function listBookmarks(_req, res) {
res.json(await service.list())
}
export async function createBookmark(req, res) {
const created = await service.create(req.body)
res.status(201).json(created)
}Central Error Handler (src/middleware/errorHandler.js)
Use one error handler to enforce consistent response format across all routes.
export function errorHandler(err, _req, res, _next) {
const status = err.status || 500
const message = err.message || "Internal Server Error"
res.status(status).json({ message })
}Mini Project: API Key Middleware (src/middleware/apiKeyAuth.js)
Add lightweight auth to your learning API. This is a practical upgrade for personal tools.
export function apiKeyAuth(req, _res, next) {
const provided = req.get('x-api-key')
if (!provided || provided !== process.env.API_KEY) {
return next({ status: 401, message: 'Unauthorized' })
}
next()
}Integration Test with Supertest (tests/bookmarks.test.js)
Verify core route behavior quickly with real HTTP requests against your app object.
import request from 'supertest'
import app from '../src/app.js'
test('GET /health returns ok', async () => {
await request(app).get('/health').expect(200, { ok: true })
})Server Entrypoint (src/server.js)
Keep process startup separate from app configuration for easier testing.
import 'dotenv/config'
import app from './app.js'
const port = process.env.PORT || 3000
app.listen(port, () => {
console.log(`API listening on http://localhost:${port}`)
})Run Express API Locally
Use a server entrypoint and environment file to run your mini project consistently.
echo "API_KEY=dev-secret" > .env
node src/server.js
curl http://localhost:3000/healthNext Learning Upgrades
These upgrades turn your snippets into a production-ready Express baseline.
1. Add pagination and sorting query parameters.
2. Add request rate limiting middleware.
3. Add OpenAPI docs for API consumers.
4. Add database migrations and seeds.
5. Add CI checks for linting and tests.