designpatterns

Post/Redirect/Get (PRG) Design Pattern - GeeksforGeeks

Intro

This pattern is particularly useful for handling form submissions and can mitigate issues caused by users refreshing or bookmarking pages that make changes to the server’s state.

Problem

Solution

How PRG Works

  1. POST Request:

    • The user submits a form.
    • The browser sends a POST request to the server.
    • The server processes the request (e.g., saving data to a database).
  2. Redirect (302 Response):

    • Instead of directly rendering a response, the server responds with a 302 Found status and a Location header pointing to a different URL (often a GET request to a confirmation page).
  3. GET Request:

    • The browser follows the redirect and makes a GET request to the new URL.
    • The server responds with the final page (e.g., a success message or the updated content).

Why Use PRG?

  • Prevents Duplicate Form Submissions:

    • Without PRG, refreshing the page after a POST request resubmits the form.
    • With PRG, refreshing only reloads the GET request, avoiding duplicate actions.
  • Improves User Experience:

    • Users can bookmark or share the final GET page without causing unintended side effects.
  • Follows REST Principles:

    • Helps maintain a clear separation between actions (POST) and retrieval (GET).

Example Scenario

Without PRG

  1. User submits a form (POST to /submit).
  2. The server processes it and returns a success page.
  3. User refreshes the page → Form gets resubmitted!

With PRG

  1. User submits a form (POST to /submit).
  2. Server processes the data and redirects (302) to /success.
  3. Browser follows the redirect and makes a GET request to /success.
  4. User refreshes /success → No duplicate submission.
const express = require("express");
const bodyParser = require("body-parser");
 
const app = express();
const PORT = 3000;
 
app.use(bodyParser.urlencoded({ extended: true }));
 
// Serve the form page
app.get("/", (req, res) => {
  res.send(`
    <h2>Post/Redirect/Get Example</h2>
    <form action="/submit" method="POST">
      <input type="text" name="name" placeholder="Enter your name" required />
      <button type="submit">Submit</button>
    </form>
  `);
});
 
// Handle form submission (POST request)
app.post("/submit", (req, res) => {
  const { name } = req.body;
  
  // Simulating saving data (e.g., to a database)
  console.log(`Received name: ${name}`);
 
  // Redirect to success page (PRG pattern)
  res.redirect(`/success?name=${encodeURIComponent(name)}`);
});
 
// Success page (GET request)
app.get("/success", (req, res) => {
  const name = req.query.name || "Guest";
  res.send(`<h2>Thank you, ${name}! Your form was submitted successfully.</h2>
            <a href="/">Go back</a>`);
});
 
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});