Request & Response Objects

Work with request data, query strings, body parsing, and send responses

The Request Object

The req object represents the HTTP request and contains properties for the request query string, parameters, body, HTTP headers, and more.

📥 Common Request Properties

req.params - Route parameters
req.query - Query string
req.body - Request body
req.headers - HTTP headers
req.method - HTTP method
req.path - URL path
req.cookies - Cookies (with parser)
req.ip - Client IP address

Working with Request Data

import express from 'express';
const app = express();

// Enable body parsing
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.post('/users/:id', (req, res) => {
  // Route parameters
  const { id } = req.params;  // /users/123 → id = "123"
  
  // Query string
  const { page, limit } = req.query;  // ?page=1&limit=10
  
  // Request body (JSON)
  const { name, email } = req.body;  // { "name": "John", "email": "..." }
  
  // Headers
  const contentType = req.headers['content-type'];
  const authHeader = req.headers.authorization;
  const userAgent = req.get('User-Agent');  // Alias for headers
  
  // Request info
  console.log(req.method);      // POST
  console.log(req.path);        // /users/123
  console.log(req.originalUrl); // /users/123?page=1
  console.log(req.baseUrl);     // Base URL if using Router
  console.log(req.hostname);    // localhost
  console.log(req.ip);          // Client IP
  console.log(req.protocol);    // http or https
  console.log(req.secure);      // true if https
  
  res.json({ id, name, email, page });
});

Request Body Parsing

// JSON body (application/json)
app.use(express.json({ limit: '10mb' }));

// URL-encoded (form submissions)
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// Raw body (webhooks)
app.use('/webhooks', express.raw({ type: 'application/json' }));

// Text body
app.use(express.text());

// File uploads - use multer
import multer from 'multer';

const upload = multer({ 
  dest: 'uploads/',
  limits: { fileSize: 5 * 1024 * 1024 } // 5MB
});

// Single file
app.post('/upload', upload.single('avatar'), (req, res) => {
  console.log(req.file);  // Uploaded file info
  console.log(req.body);  // Other form fields
  res.json({ filename: req.file?.filename });
});

// Multiple files
app.post('/gallery', upload.array('photos', 10), (req, res) => {
  console.log(req.files); // Array of files
  res.json({ count: (req.files as Express.Multer.File[]).length });
});

The Response Object

app.get('/demo', (req, res) => {
  // Set status code
  res.status(200);
  res.status(201);  // Created
  res.status(400);  // Bad Request
  res.status(404);  // Not Found
  res.status(500);  // Server Error
  
  // Send response
  res.send('Plain text');           // Auto content-type
  res.json({ data: 'value' });      // JSON response
  res.sendStatus(204);              // Status only, no body
  
  // Chaining
  res.status(201).json({ id: 1 });
  
  // Set headers
  res.set('X-Custom-Header', 'value');
  res.setHeader('Cache-Control', 'no-store');
  res.type('application/json');     // Content-Type shortcut
  
  // Cookies
  res.cookie('session', 'abc123', {
    httpOnly: true,
    secure: true,
    maxAge: 24 * 60 * 60 * 1000  // 1 day
  });
  res.clearCookie('session');
  
  // Redirect
  res.redirect('/new-location');
  res.redirect(301, '/permanent-redirect');
  res.redirect('back');  // Previous page
});

Response Methods

// JSON response (most common)
app.get('/api/users', (req, res) => {
  res.json({ users: [], count: 0 });
});

// Send file download
app.get('/download/:filename', (req, res) => {
  const filePath = `./files/${req.params.filename}`;
  res.download(filePath, 'custom-name.pdf');
});

// Send file inline
app.get('/view/:filename', (req, res) => {
  res.sendFile('/absolute/path/to/file.pdf');
});

// Streaming response
app.get('/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/plain');
  res.write('Chunk 1\n');
  res.write('Chunk 2\n');
  res.end('Final chunk');
});

// Render template (with view engine)
app.set('view engine', 'ejs');
app.get('/page', (req, res) => {
  res.render('template', { title: 'My Page', user: req.user });
});

// Content negotiation
app.get('/data', (req, res) => {
  res.format({
    'application/json': () => res.json({ data: 'json' }),
    'text/html': () => res.send('

HTML

'), 'text/plain': () => res.send('Plain text'), default: () => res.status(406).send('Not Acceptable') }); });

TypeScript Request Types

import { Request, Response } from 'express';

// Define types for all parts of the request
interface CreateUserParams {
  // Empty for POST with no route params
}

interface CreateUserBody {
  name: string;
  email: string;
  password: string;
}

interface CreateUserQuery {
  sendWelcomeEmail?: string;
}

interface UserResponse {
  id: number;
  name: string;
  email: string;
}

// Request<Params, ResBody, ReqBody, Query>
app.post('/users',
  (req: Request<CreateUserParams, UserResponse, CreateUserBody, CreateUserQuery>, 
   res: Response<UserResponse>) => {
    const { name, email, password } = req.body;  // Typed!
    const { sendWelcomeEmail } = req.query;      // Typed!
    
    const user: UserResponse = {
      id: 1,
      name,
      email
    };
    
    res.status(201).json(user);
  }
);

// Extend Request for custom properties
interface AuthRequest extends Request {
  user?: {
    id: string;
    email: string;
  };
}

app.get('/profile', authenticate, (req: AuthRequest, res) => {
  res.json({ user: req.user });
});

Request Validation

// Using express-validator
import { body, param, query, validationResult } from 'express-validator';

app.post('/users',
  [
    body('email').isEmail().normalizeEmail(),
    body('password').isLength({ min: 8 }),
    body('name').trim().notEmpty(),
  ],
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // Proceed with valid data
    res.status(201).json(req.body);
  }
);

// Using Zod
import { z } from 'zod';

const userSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  password: z.string().min(8),
});

app.post('/users', (req, res) => {
  const result = userSchema.safeParse(req.body);
  
  if (!result.success) {
    return res.status(400).json({ errors: result.error.issues });
  }
  
  const { name, email, password } = result.data;  // Typed!
  res.status(201).json({ name, email });
});

📖 express-validator Documentation →

✅ Best Practices

  • • Always validate and sanitize user input
  • • Use proper HTTP status codes (201 for created, 204 for no content)
  • • Set appropriate Content-Type headers
  • • Use res.json() for API responses
  • • Type your request/response with TypeScript
  • • Never trust req.body - always validate first