Learning Objectives
Access GET query parameters via req.query
Parse URL-encoded POST data with express.urlencoded() middleware
Parse JSON request bodies with express.json() middleware
Compare PHP superglobals ($_GET, $_POST) to Express equivalents
Support both form-encoded and JSON submissions for progressive enhancement
Validate and sanitize user input to prevent XSS attacks
PHP vs Node.js: Form Data Access
In PHP, form data magically appears in superglobals. In Node.js/Express, you must explicitly configure middleware to parse it.
Scenario
PHP
Express
GET parameters?name=Alice
$_GET['name']
req.query.name
POST form data
$_POST['name']
req.body.name (requires middleware)
JSON body
json_decode(file_get_contents('php://input'))
req.body (requires middleware)
GET Parameters (Query Strings)
GET data is available immediately in Express via req.query:
// URL: /search?q=nodejs&page=2
app.get('/search', (req, res) => {
const query = req.query.q; // 'nodejs'
const page = req.query.page; // '2' (always a string!)
res.json({
query: query,
page: parseInt(page) || 1
});
});
Important: Query parameters are always strings! Use parseInt() or Number() to convert to numbers.
POST Form Data (URL-Encoded)
Traditional HTML forms submit data as application/x-www-form-urlencoded. Express needs middleware to parse this:
const express = require('express');
const app = express();
// Enable parsing of URL-encoded form data
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
const username = req.body.username;
const password = req.body.password;
// Validate and process...
res.json({ message: `Hello, ${username}!` });
});
The HTML form:
JSON Body (API Requests)
Many APIs accept JSON instead of form-encoded data. Add the JSON middleware:
JSON requires JavaScript: Unlike URL-encoded forms which browsers submit natively, sending JSON requires JavaScript to encode the payload. If you want progressive enhancement (forms that work without JS), use URL-encoded forms. For maximum flexibility, design your endpoints to accept both formats.
// Enable parsing of JSON bodies
app.use(express.json());
app.post('/api/users', (req, res) => {
const userData = req.body;
console.log(userData); // { name: 'Alice', email: 'alice@example.com' }
res.status(201).json({
message: 'User created',
user: userData
});
});
Client-side JavaScript:
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
});
Supporting Both Methods (Progressive Enhancement)
By enabling both middleware, your endpoints can accept either format. This supports progressive enhancement: the form works without JavaScript, but JavaScript clients can send JSON for richer interactions.
const express = require('express');
const app = express();
// Middleware for both types of requests
app.use(express.json()); // JSON bodies
app.use(express.urlencoded({ extended: true })); // Form bodies
app.use(express.static('public')); // Static files
// Now req.body works for both JSON and form data!
// The same endpoint can handle:
// - Traditional form submission (no JS required)
// - fetch() with JSON (JS-enhanced experience)
Progressive Enhancement: Your form works for all users (including those with JavaScript disabled or on slow connections), while JavaScript users get enhanced functionality. This is a best practice for robust web applications.
Complete Form Handling Example
// form-demo.js
const express = require('express');
const app = express();
const PORT = 3000;
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
// Handle GET request (display search results)
app.get('/search', (req, res) => {
const query = req.query.q || '';
res.json({
type: 'GET',
searchQuery: query,
message: query ? `Searching for: ${query}` : 'No query provided'
});
});
// Handle POST request (form submission)
app.post('/submit', (req, res) => {
const { username, email, message } = req.body;
// Basic validation
if (!username || !email) {
return res.status(400).json({
error: 'Username and email are required'
});
}
res.json({
type: 'POST',
received: { username, email, message },
success: true
});
});
// Handle JSON API request
app.post('/api/data', (req, res) => {
console.log('Received JSON:', req.body);
res.json({
type: 'JSON API',
received: req.body,
timestamp: new Date().toISOString()
});
});
app.listen(PORT, () => {
console.log(`Form demo running at http://localhost:${PORT}`);
console.log('Open http://localhost:${PORT}/form.html to test');
});
Input Validation
Never trust user input! Always validate and sanitize:
app.post('/register', (req, res) => {
const { username, email, age } = req.body;
// Type checking
if (typeof username !== 'string') {
return res.status(400).json({ error: 'Invalid username' });
}
// Length validation
if (username.length < 3 || username.length > 50) {
return res.status(400).json({ error: 'Username must be 3-50 characters' });
}
// Email format (basic check)
if (!email || !email.includes('@')) {
return res.status(400).json({ error: 'Invalid email' });
}
// Number conversion and range
const ageNum = parseInt(age);
if (isNaN(ageNum) || ageNum < 0 || ageNum > 150) {
return res.status(400).json({ error: 'Invalid age' });
}
// All valid!
res.json({ success: true, username, email, age: ageNum });
});
Production tip: For real applications, use a validation library like express-validator or joi instead of manual validation.
XSS Prevention
When displaying user input in HTML, always escape it to prevent Cross-Site Scripting (XSS) attacks:
// DANGEROUS - Don't do this!
app.get('/greet', (req, res) => {
res.send(`Hello, ${req.query.name}! `);
});
// Attack: /greet?name=
// SAFE - Escape HTML entities
function escapeHtml(text) {
return text
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
app.get('/greet', (req, res) => {
const safeName = escapeHtml(req.query.name || 'Guest');
res.send(`Hello, ${safeName}! `);
});
Security: In the PHP tutorial, we discussed how PHP's htmlspecialchars() escapes output. Node.js has no built-in equivalent; you must use a library or function like above. Template engines like EJS or Handlebars escape by default.
Summary
Task
Code
Enable form parsing
app.use(express.urlencoded({ extended: true }))
Enable JSON parsing
app.use(express.json())
Get query params
req.query.paramName
Get POST/JSON body
req.body.fieldName
Validate input
Check type, length, format before using
Prevent XSS
Escape HTML entities or use a template engine
Key Takeaways
Unlike PHP's automatic superglobals, Express requires explicit middleware (express.urlencoded() and express.json()) to parse incoming request bodies.
GET parameters are available via req.query without any middleware, but POST/JSON bodies require middleware to populate req.body.
Enabling both URL-encoded and JSON middleware lets the same endpoint accept traditional form submissions and JavaScript fetch() calls, supporting progressive enhancement.
Always validate user input on the server: check types, lengths, and formats before processing.
Node.js has no built-in XSS protection — you must escape HTML output manually or use a template engine that escapes by default.