Routing and HTTP Methods
Routing maps incoming requests — identified by HTTP method and URL path — to handler functions. Defining clean, RESTful routes is one of the most important skills in API development.
HTTP methods and their meaning
Section titled “HTTP methods and their meaning”HTTP defines several methods, each with a semantic meaning:
| Method | Meaning | Example |
|---|---|---|
GET | Retrieve data (read-only, no body) | Get all posts, get one post |
POST | Create a new resource | Create a post |
PUT | Replace a resource entirely | Replace a post |
PATCH | Update part of a resource | Update just the title |
DELETE | Remove a resource | Delete a post |
Express has a method for each: app.get(), app.post(), app.put(), app.patch(), app.delete().
RESTful route conventions
Section titled “RESTful route conventions”REST (Representational State Transfer) is a set of conventions for naming API routes. Following them makes your API intuitive for anyone who has used an API before:
GET /posts → list all postsGET /posts/:id → get one postPOST /posts → create a postPATCH /posts/:id → update a postDELETE /posts/:id → delete a post
GET /posts/:id/comments → list comments for a postPOST /posts/:id/comments → add a commentThe pattern: plural noun for the collection, /:id for a single resource, nested paths for sub-resources.
Defining routes
Section titled “Defining routes”import express from 'express'
const app = express()app.use(express.json())
// In-memory store for this exampleconst posts: { id: number; title: string; body: string }[] = []let nextId = 1
app.get('/posts', (req, res) => { res.json(posts)})
app.get('/posts/:id', (req, res) => { const post = posts.find(p => p.id === parseInt(req.params.id)) if (!post) return res.status(404).json({ error: 'Not found' }) res.json(post)})
app.post('/posts', (req, res) => { const { title, body } = req.body const post = { id: nextId++, title, body } posts.push(post) res.status(201).json(post)})
app.patch('/posts/:id', (req, res) => { const post = posts.find(p => p.id === parseInt(req.params.id)) if (!post) return res.status(404).json({ error: 'Not found' }) if (req.body.title) post.title = req.body.title if (req.body.body) post.body = req.body.body res.json(post)})
app.delete('/posts/:id', (req, res) => { const index = posts.findIndex(p => p.id === parseInt(req.params.id)) if (index === -1) return res.status(404).json({ error: 'Not found' }) posts.splice(index, 1) res.sendStatus(204)})app.all() and wildcard routes
Section titled “app.all() and wildcard routes”Match any HTTP method or act as a catch-all:
// Handle all methods on a pathapp.all('/legacy', (req, res) => { res.status(410).json({ error: 'This endpoint is gone' })})
// 404 catch-all — must be lastapp.use((req, res) => { res.status(404).json({ error: 'Route not found' })})Route order matters
Section titled “Route order matters”Express matches routes in the order they are defined. Put specific routes before catch-alls:
// ✅ Specific route firstapp.get('/posts/trending', handler)app.get('/posts/:id', handler) // `:id` would match 'trending' if defined firstExercise
Section titled “Exercise”- Test your in-memory posts API with all five routes using curl or Thunder Client.
- Create two posts, update one, retrieve the updated one, then delete it.
- What happens when you request
GET /posts/999(a non-existent id)? - Add the 404 catch-all route at the bottom and test requesting a non-existent path.
- HTTP methods have semantic meanings: GET reads, POST creates, PATCH updates, DELETE removes.
- RESTful conventions: plural noun for collections (
/posts),/:idfor single resources. - Routes are matched in order — put specific routes before wildcards.
app.use(handler)at the end catches all unmatched routes — useful for 404 responses.