1// REST: Resources, HTTP verbs, status codes, stateless
2// Express REST API — clean resource design
3
4import express from 'express';
5const app = express();
6app.use(express.json());
7
8// GET /posts — collection resource
9app.get('/posts', async (req, res) => {
10 const { page = '1', limit = '20', tag } = req.query;
11 const posts = await db.posts.findAll({
12 page: parseInt(page as string),
13 limit: Math.min(parseInt(limit as string), 100),
14 filter: tag ? { tag: tag as string } : undefined,
15 });
16 res.json({ data: posts, page: parseInt(page as string), total: posts.length });
17});
18
19// GET /posts/:id — single resource
20app.get('/posts/:id', async (req, res) => {
21 const post = await db.posts.findById(req.params.id);
22 if (!post) return res.status(404).json({ error: 'Post not found' });
23 res.json(post);
24});
25
26// POST /posts — create
27app.post('/posts', async (req, res) => {
28 const post = await db.posts.create(req.body);
29 res.status(201)
30 .set('Location', `/posts/${post.id}`)
31 .json(post);
32});
33
34// PATCH /posts/:id — partial update (not PUT)
35app.patch('/posts/:id', async (req, res) => {
36 const post = await db.posts.update(req.params.id, req.body);
37 if (!post) return res.status(404).json({ error: 'Not found' });
38 res.json(post);
39});
40
41// DELETE /posts/:id — idempotent delete
42app.delete('/posts/:id', async (req, res) => {
43 await db.posts.delete(req.params.id);
44 res.status(204).send(); // No body on delete
45});
46
47declare const db: any;