1 · Structure and rendering · 30 MIN
Bounded bodies and runtime validation
An HTTP payload needs both a size limit and a shape contract.
express.json enforces a configured parser limit before a route handles the body. Zod validates the parsed object and trims the title. A preview route makes the transformation easy to test without introducing persistence. Strict schemas reject unrecognized fields, avoiding accidental acceptance of client-supplied ownership fields later. Before turning this into an account write, add authenticated ownership, origin/CSRF protections appropriate to cookie authentication, rate limits and a database transaction where required.
Reject unknown fields and titles shorter than three trimmed characters.
Read the example
// npm install express zod
import express from 'express';
import {z} from 'zod';
const app=express();app.use(express.json({limit:'16kb'}));
const Input=z.object({title:z.string().trim().min(3).max(80)}).strict();
app.post('/preview',(req,res)=>{const parsed=Input.safeParse(req.body);if(!parsed.success)return res.status(400).json({error:'Invalid title'});return res.json({preview:parsed.data.title})});
app.listen(3000,'127.0.0.1');Check the expected output
A valid title returns its trimmed preview; a schema mismatch returns 400; the parser rejects oversized JSON.
Your challenge
Add explicit JSON error responses for malformed and oversized bodies while keeping parser limits in place.
Solution cost: O(b) parsing for a bounded b-byte body. time · O(b) request representation. space
Common trap
TypeScript request interfaces do not validate incoming JSON.
Study the project implementation
// npm install express zod
import express from 'express';
import {z} from 'zod';
const app=express();app.use(express.json({limit:'16kb'}));
const Input=z.object({title:z.string().trim().min(3).max(80)}).strict();
app.post('/preview',(req,res)=>{const parsed=Input.safeParse(req.body);if(!parsed.success)return res.status(400).json({error:'Invalid title'});return res.json({preview:parsed.data.title})});
app.listen(3000,'127.0.0.1');Further reading: Official documentation
Next lesson: Express async failures and final error handling →