Node.js Form Handling
Forms collect information from visitors, such as names, emails, and messages. Express receives that information, reads it, and responds. This lesson shows the full path from the form to the server.
How a Form Travels
A form works like a paper slip dropped into a mailbox. The visitor fills the slip, the browser carries it, and the server reads it.
+-----------+ submit +-----------------+ read +----------+
| HTML form | ---------> | Express route | -------> | req.body |
+-----------+ POST +-----------------+ +----------+
|
v
Response or redirect
GET and POST
- GET places form data in the address bar. Use it for searches.
- POST hides form data inside the request body. Use it for logins, sign-ups, and messages.
Build the HTML Form
Save this file as public/contact.html.
<form action="/contact" method="POST">
<label>Name</label>
<input type="text" name="fullName" required>
<label>Email</label>
<input type="email" name="email" required>
<label>Message</label>
<textarea name="message"></textarea>
<button type="submit">Send</button>
</form>The name attribute of each field becomes the key on the server. A field without a name never reaches Express.
Read the Form Data
Express needs a helper called middleware to decode form data. The express.urlencoded helper handles standard HTML forms.
const express = require("express");
const app = express();
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.post("/contact", (req, res) => {
const { fullName, email, message } = req.body;
console.log(fullName, email, message);
res.send("Thanks, " + fullName + "!");
});
app.listen(3000);The object req.body holds one key per form field.
Form field name --> req.body key fullName --> req.body.fullName email --> req.body.email message --> req.body.message
Read JSON Data
Mobile apps and JavaScript code often send JSON instead of form data. Add the JSON helper for those requests.
app.use(express.json());Check the Data
Never trust data from a visitor. Check each field before you use it.
app.post("/contact", (req, res) => {
const { fullName, email, message } = req.body;
if (!fullName || !email) {
return res.status(400).send("Name and email are required.");
}
if (!email.includes("@")) {
return res.status(400).send("Enter a valid email.");
}
if (message && message.length > 500) {
return res.status(400).send("Message is too long.");
}
res.send("Message received.");
});Status code 400 tells the browser that the request has a problem.
Redirect After Success
A page that answers a POST request can show the form again when the visitor refreshes, which resends the data. A redirect prevents that problem. This pattern is called Post, Redirect, Get.
app.post("/contact", (req, res) => {
// save the data here
res.redirect("/thanks.html");
});
Browser --POST--> Server Browser <--redirect-- Server Browser --GET /thanks.html--> Server
Handle a Search Form with GET
<form action="/search" method="GET">
<input type="text" name="q">
<button>Search</button>
</form>
app.get("/search", (req, res) => {
const term = req.query.q || "";
res.send("You searched for: " + term);
});GET data arrives in req.query, not in req.body.
Protect Output
Visitors can type HTML tags into a form. Printing that text straight onto a page lets harmful scripts run. Template engines escape text automatically. Escape manual output yourself.
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
}Common Problems
req.body Is Undefined
The parsing helper is missing, or it sits below your route. Place app.use lines above the routes.
Fields Arrive Empty
Check the name attribute on each input.
Practice Tasks
- Build a sign-up form with name, email, and age fields.
- Reject an age below 18 with a clear message.
- Redirect to a thank-you page after a valid submission.
