Navigation

Node.js

How to Send Different Response Types (JSON, HTML, File)

Send various response types in Express.js - JSON data, HTML pages, file downloads, and redirects. Master Express response methods for different client needs.

Table Of Contents

Problem

You need to send different types of responses from your Express.js routes - JSON for APIs, HTML for web pages, file downloads, and handle various content types properly.

Solution

const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();

// 1. JSON Response
app.get('/api/users', (req, res) => {
  const users = [
    { id: 1, name: 'John', email: 'john@example.com' },
    { id: 2, name: 'Jane', email: 'jane@example.com' }
  ];
  
  res.json({
    success: true,
    data: users,
    count: users.length
  });
});

// 2. HTML Response
app.get('/users', (req, res) => {
  const html = `
    <!DOCTYPE html>
    <html>
      <head><title>Users</title></head>
      <body>
        <h1>User List</h1>
        <ul>
          <li>John (john@example.com)</li>
          <li>Jane (jane@example.com)</li>
        </ul>
      </body>
    </html>
  `;
  
  res.setHeader('Content-Type', 'text/html');
  res.send(html);
});

// 3. Plain Text Response
app.get('/api/status', (req, res) => {
  res.type('text/plain');
  res.send('Server is running OK');
});

// 4. File Download
app.get('/download/report', (req, res) => {
  const filePath = path.join(__dirname, 'files', 'report.pdf');
  
  // Option 1: Download with custom filename
  res.download(filePath, 'monthly-report.pdf', (err) => {
    if (err) {
      console.error('Download error:', err);
      res.status(404).json({ error: 'File not found' });
    }
  });
});

// 5. File Streaming (for large files)
app.get('/stream/video', (req, res) => {
  const filePath = path.join(__dirname, 'files', 'video.mp4');
  
  if (!fs.existsSync(filePath)) {
    return res.status(404).json({ error: 'Video not found' });
  }
  
  const stat = fs.statSync(filePath);
  const fileSize = stat.size;
  const range = req.headers.range;
  
  if (range) {
    // Handle range requests for video seeking
    const parts = range.replace(/bytes=/, '').split('-');
    const start = parseInt(parts[0], 10);
    const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
    const chunksize = (end - start) + 1;
    
    const file = fs.createReadStream(filePath, { start, end });
    
    res.writeHead(206, {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'Accept-Ranges': 'bytes',
      'Content-Length': chunksize,
      'Content-Type': 'video/mp4',
    });
    
    file.pipe(res);
  } else {
    res.writeHead(200, {
      'Content-Length': fileSize,
      'Content-Type': 'video/mp4',
    });
    fs.createReadStream(filePath).pipe(res);
  }
});

// 6. XML Response
app.get('/api/users.xml', (req, res) => {
  const xml = `<?xml version="1.0" encoding="UTF-8"?>
    <users>
      <user id="1">
        <name>John</name>
        <email>john@example.com</email>
      </user>
      <user id="2">
        <name>Jane</name>
        <email>jane@example.com</email>
      </user>
    </users>`;
  
  res.set('Content-Type', 'application/xml');
  res.send(xml);
});

// 7. Redirect Responses
app.get('/old-page', (req, res) => {
  // Permanent redirect (301)
  res.redirect(301, '/new-page');
});

app.get('/login', (req, res) => {
  // Temporary redirect (302) - default
  res.redirect('/auth/login');
});

// 8. Status-only Response
app.post('/api/ping', (req, res) => {
  res.sendStatus(204); // No Content
});

// 9. Custom Headers Response
app.get('/api/data', (req, res) => {
  res.set({
    'X-API-Version': '1.0',
    'Cache-Control': 'no-cache',
    'Access-Control-Allow-Origin': '*'
  });
  
  res.json({ message: 'Data with custom headers' });
});

// 10. Error Responses
app.get('/api/error', (req, res) => {
  res.status(400).json({
    error: 'Bad Request',
    message: 'Invalid parameters provided',
    code: 'INVALID_PARAMS'
  });
});

// 11. Content Negotiation
app.get('/content', (req, res) => {
  const acceptHeader = req.headers.accept || '';
  
  if (acceptHeader.includes('application/json')) {
    res.json({ message: 'JSON response', format: 'json' });
  } else if (acceptHeader.includes('application/xml')) {
    res.set('Content-Type', 'application/xml');
    res.send('<?xml version="1.0"?><message>XML response</message>');
  } else {
    res.send('<h1>HTML Response</h1><p>Default HTML format</p>');
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Test different response types:

# JSON response
curl -H "Accept: application/json" http://localhost:3000/content

# XML response
curl -H "Accept: application/xml" http://localhost:3000/content

# Download file
curl -O http://localhost:3000/download/report

Explanation

Express provides specific methods for different response types: res.json() for JSON, res.send() for HTML/text, res.download() for files, and res.redirect() for redirects.

res.set() or res.setHeader() customize response headers. For file streaming, use fs.createReadStream().pipe(res) for large files. Content negotiation with Accept headers allows the same endpoint to serve different formats based on client preferences.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Node.js