Tutorials Logic, IN info@tutorialslogic.com

Servlet HTTP Methods GET, POST, PUT, DELETE

Method Dispatch

HttpServlet.service() examines the request method and dispatches standard HTTP requests to doGet(), doPost(), doPut(), doPatch(), doDelete(), doHead(), doOptions(), or doTrace(). Jakarta Servlet 6.1 added a dedicated doPatch() method, so current applications do not need to override service() merely to support PATCH.

A handler name is only the entry point. Correct design also depends on HTTP semantics: whether the operation is safe, whether repeating it should have the same intended effect, which status describes the result, and whether a response body is appropriate.

Servlet 6.1 Handlers

Override only the methods the resource supports. The default HttpServlet implementation returns an error for unsupported methods, while doOptions can report supported methods through the Allow header. GET should retrieve a representation without causing accountable side effects; HEAD returns the corresponding headers without a body.

Handler Intent Safe Idempotent
doGet() Read a representation Yes Yes
doPost() Create or execute a command No Usually no
doPut() Replace resource state at a known URI No Yes
doPatch() Apply a partial modification No Not guaranteed
doDelete() Remove a resource No Yes in intended effect
doHead() Read headers corresponding to GET Yes Yes

doGet and doPost

doGet and doPost
package com.example;

import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.*;

@WebServlet("/form")
public class FormServlet extends HttpServlet {

    // GET: Show the form
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("<!DOCTYPE html><html><body>");
        out.println("<h2>Registration Form</h2>");
        out.println("<form method='post' action='/form'>");
        out.println("  Name: <input type='text' name='name'/><br/>");
        out.println("  Email: <input type='email' name='email'/><br/>");
        out.println("  <button type='submit'>Register</button>");
        out.println("</form></body></html>");
    }

    // POST: Process the form
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        String name  = req.getParameter("name");
        String email = req.getParameter("email");

        // Validate
        if (name == null || name.trim().isEmpty()) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Name is required");
            return;
        }

        // Process (save to DB, etc.)
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        out.println("<h2>Registration Successful!</h2>");
        out.println("<p>Name: " + name + "</p>");
        out.println("<p>Email: " + email + "</p>");
    }
}

Status and Headers

Return 200 when a representation is included, 201 when a resource was created, and 204 when the operation succeeded without a response body. A 201 response should normally identify the new resource with a Location header. Use 400 for malformed input, 401 when authentication is required, 403 when an authenticated caller lacks permission, 404 when the resource is absent, 405 when the resource does not allow that method, and 409 when current state conflicts with the operation.

Do not catch every failure and return 200 with an error string. Clients, caches, gateways, and monitoring tools use status codes to understand the exchange. Likewise, do not return a Java stack trace or database exception as an API body.

sendRedirect vs RequestDispatcher.forward

sendRedirect vs RequestDispatcher.forward
@WebServlet("/redirect-demo")
public class RedirectServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        String action = req.getParameter("action");

        if ("redirect".equals(action)) {
            // sendRedirect: client-side redirect (new HTTP request)
            // URL changes in browser, request attributes are lost
            // Can redirect to external URLs
            resp.sendRedirect("https://example.com");
            // OR: resp.sendRedirect(req.getContextPath() + "/home");

        } else if ("forward".equals(action)) {
            // RequestDispatcher.forward: server-side forward (same request)
            // URL does NOT change in browser, request attributes are preserved
            // Can only forward within the same web application
            req.setAttribute("message", "Forwarded from RedirectServlet");
            RequestDispatcher rd = req.getRequestDispatcher("/WEB-INF/views/result.jsp");
            rd.forward(req, resp);

        } else if ("include".equals(action)) {
            // RequestDispatcher.include: includes another resource's output
            // Both servlets contribute to the response
            RequestDispatcher rd = req.getRequestDispatcher("/header.jsp");
            rd.include(req, resp);
            resp.getWriter().println("<p>Main content here</p>");

        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown action");
        }
    }
}

PUT and PATCH

PUT expresses the desired complete state of a resource at the target URI. Repeating the same PUT should leave the resource in the same intended state. PATCH carries a set of partial changes, so its idempotency depends on the patch format and operation. Incrementing a counter is not idempotent; setting a display name to a fixed value can be.

Servlet 6.1 PATCH Handler

Servlet 6.1 PATCH Handler
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;

@WebServlet("/api/users/*")
public class UserServlet extends HttpServlet {
    @Override
    protected void doPatch(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        String id = req.getPathInfo();
        if (id == null || id.length() < 2) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "User id is required");
            return;
        }

        // Parse and validate a patch document before applying it.
        resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
    }
}

Concurrency and Retries

One servlet instance commonly handles concurrent requests. Keep request-specific values in local variables and move shared mutable state into thread-safe services or a database transaction. Idempotent method semantics do not automatically make an implementation race-free.

Networks can fail after the server changes state but before the client receives the response. For commands that may be retried, consider an idempotency key, a uniqueness constraint, or an operation identifier so the server can recognize duplicate submissions.

  • Reject an unsupported method with 405 and an accurate Allow header.
  • Validate Content-Type before parsing a request body.
  • Authorize the concrete resource, not only the URL pattern.
  • Use transactions when one request changes related records together.
Before you move on

Method Design Review

5 checks
  • Match the handler to the operation rather than routing every action through POST.
  • State whether the operation is safe and whether retries preserve its intended effect.
  • Return a status, body, and Location header that agree with the result.
  • Use the Servlet 6.1 doPatch() method for partial updates.
  • Keep mutable request state out of servlet instance fields.

HTTP Contract Mistakes

  • GET changes database state

    Use a state-changing method and protect it against CSRF where browser credentials are involved.
  • Every response is 200

    Return the status that describes creation, validation failure, absence, conflict, or empty success.
  • PATCH overrides service()

    On Jakarta Servlet 6.1, override doPatch() directly.

Try this next

Design a Resource

0 of 3 completed

  1. Choose handlers and expected statuses for list, create, replace, partially update, and delete operations.
  2. Send the same PUT and DELETE twice and explain which state and status are acceptable after each request.
  3. Return 415 when a JSON endpoint receives an incompatible Content-Type.

Method Semantics

Yes. HttpServlet in Servlet 6.1 defines doPatch(HttpServletRequest, HttpServletResponse).

It can still be idempotent because repeating the request leaves the resource absent; identical response codes are not required.

No. Use 201 when a resource is created; commands or processing operations may return another success status.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.