🌐 Section 6 · Question #9

What HTTP status codes do you know

An HTTP Status Code is a 3-digit integer transmitted by the server in the initial response status line to inform the client of the outcome of its request (RFC 9110).


🟢 Junior Level

An HTTP Status Code is a 3-digit integer transmitted by the server in the initial response status line to inform the client of the outcome of its request (RFC 9110).

The first digit defines the response class:

Class Category Semantic Meaning
1xx Informational Request received, protocol handshake or transfer continuing (e.g., 100 Continue).
2xx Success The action was successfully received, understood, and accepted.
3xx Redirection Further action must be taken by the client to complete the request.
4xx Client Error The request contains bad syntax or cannot be fulfilled due to client fault.
5xx Server Error The server failed to fulfill an apparently valid request due to internal error.
General Rule of Thumb:
• 2xx: Everything worked as intended.
• 4xx: The CLIENT made an error (bad input, unauthenticated, forbidden, missing resource).
• 5xx: The SERVER failed (unhandled Java exception, database crash, network timeout).

Essential Status Codes Every Developer Must Know

  • 200 OK: Standard response for successful requests with a response body.
  • 201 Created: The resource was successfully created (standard for POST). Usually accompanied by a Location header pointing to the new URI.
  • 204 No Content: The request succeeded, but the response intentionally contains no body (standard for DELETE or PUT).
  • 301 Moved Permanently: The target resource has been permanently assigned a new URI.
  • 302 Found: Temporary redirect to a different URI.
  • 400 Bad Request: Syntactic malformation (malformed JSON, invalid query parameters).
  • 401 Unauthorized: The request lacks valid authentication credentials (“Who are you?”).
  • 403 Forbidden: The client is authenticated, but lacks sufficient permissions for the resource (“You are not allowed here”).
  • 404 Not Found: The requested resource URI does not exist on the server.
  • 500 Internal Server Error: An unhandled exception or bug occurred on the server.
  • 503 Service Unavailable: The server is temporarily overloaded or undergoing maintenance.

🟡 Middle Level

Protocol Nuances & Code Differentiation (RFC 9110)

1. Success Variations (2xx)

  • 202 Accepted: The request has been accepted for processing, but processing is not yet complete. Standard in asynchronous architectures (message queues, batch exports). The response includes a polling status URI or correlation ID.
  • 206 Partial Content: Returned when the client requests a specific byte slice via the Range header (essential for resuming interrupted downloads and video streaming).

2. The Redirection Revolution: 307 & 308 vs. Legacy 301 & 302

Historically, web browsers erroneously mutated POST requests into GET when receiving 301 or 302 redirects. To resolve this ambiguity, RFC 9110 standardized:

  • 303 See Other: Explicitly instructs the client to retrieve the redirected resource using GET (the foundation of the Post/Redirect/Get pattern).
  • 307 Temporary Redirect: Temporary redirect that strictly preserves the original HTTP method and body (POST remains POST).
  • 308 Permanent Redirect: Permanent redirect that strictly preserves the original HTTP method and body.
  • 304 Not Modified: Returned for conditional requests (If-None-Match or If-Modified-Since). The payload is empty; the client uses its cached representation.

3. Client Errors (4xx)

  • 401 Unauthorized vs. 403 Forbidden:
    • 401 Unauthorized must include a WWW-Authenticate header specifying supported challenge schemes. It denotes an authentication failure (missing or invalid token).
    • 403 Forbidden denotes an authorization failure (identity is established, but RBAC/ABAC policies deny access). Retrying with the same credentials will fail.
  • 400 Bad Request vs. 422 Unprocessable Content:
    • 400 Bad Request: Syntactic failure. The server cannot parse the payload (broken JSON, illegal byte sequences).
    • 422 Unprocessable Content (RFC 9110 / RFC 4918): Semantic failure. The JSON is well-formed, but business constraints or Bean Validations failed (e.g., negative price, invalid email format).
  • 409 Conflict: State collision with existing resource data (e.g., duplicate unique email on registration, or optimistic locking version divergence).
  • 410 Gone: The resource previously existed but has been intentionally and permanently removed without a forwarding address.
  • 412 Precondition Failed: Conditional header check failed (e.g., If-Match did not match current ETag).
  • 415 Unsupported Media Type: Server rejects the payload format sent in Content-Type (e.g., client sent XML, server requires JSON).
  • 429 Too Many Requests: Rate limiter triggered; server should supply Retry-After: <seconds>.

4. Server Errors (5xx)

  • 502 Bad Gateway: An edge proxy (Nginx, Envoy, Cloudflare) received an invalid response or a dropped TCP connection from the upstream application.
  • 503 Service Unavailable: Server is temporarily down due to traffic overload or maintenance.
  • 504 Gateway Timeout: The edge proxy established a connection, but the upstream application failed to reply within the timeout threshold (proxy_read_timeout).

🔴 Senior Level

Standardized Error Representation: RFC 9457 (Problem Details for HTTP APIs)

Returning proprietary JSON error formats ({"error": "not found", "code": 101}) is an anti-pattern. Spring Boot 3 natively implements RFC 9457 (superseding RFC 7807) using ProblemDetail (Content-Type: application/problem+json):

package com.example.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.URI;
import java.time.Instant;
import java.util.Map;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 1. DTO Validation Errors -> 422 Unprocessable Content
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ProblemDetail handleValidationException(MethodArgumentNotValidException ex) {
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
                HttpStatus.UNPROCESSABLE_ENTITY, 
                "Validation failed for one or more fields"
        );
        problem.setTitle("Validation Failed");
        problem.setType(URI.create("https://api.example.com/errors/validation-failed"));
        problem.setProperty("timestamp", Instant.now());

        Map<String, String> invalidFields = ex.getBindingResult().getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,
                        fe -> fe.getDefaultMessage() != null ? fe.getDefaultMessage() : "Invalid value",
                        (existing, replacement) -> existing
                ));

        problem.setProperty("invalidFields", invalidFields);
        return problem;
    }

    // 2. Business Conflict -> 409 Conflict
    @ExceptionHandler(UserAlreadyExistsException.class)
    public ProblemDetail handleUserExistsException(UserAlreadyExistsException ex) {
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
                HttpStatus.CONFLICT, 
                ex.getMessage()
        );
        problem.setTitle("Resource Conflict");
        problem.setType(URI.create("https://api.example.com/errors/user-conflict"));
        problem.setProperty("timestamp", Instant.now());
        return problem;
    }

    // 3. Unhandled Server Exceptions -> 500 Internal Server Error (Zero stack trace leaks!)
    @ExceptionHandler(Exception.class)
    public ProblemDetail handleGenericException(Exception ex) {
        ProblemDetail problem = ProblemDetail.forStatusAndDetail(
                HttpStatus.INTERNAL_SERVER_ERROR,
                "An unexpected internal error occurred. Please contact customer support."
        );
        problem.setTitle("Internal Server Error");
        problem.setType(URI.create("https://api.example.com/errors/internal"));
        problem.setProperty("timestamp", Instant.now());
        return problem;
    }
}

Standard RFC 9457 JSON returned to client:

{
  "type": "https://api.example.com/errors/validation-failed",
  "title": "Validation Failed",
  "status": 422,
  "detail": "Validation failed for one or more fields",
  "instance": "/api/v1/users",
  "timestamp": "2026-09-27T08:00:00Z",
  "invalidFields": {
    "email": "Must be a valid email address",
    "age": "Must be greater than or equal to 18"
  }
}

Highload Infrastructure & Observability Considerations

  1. Negative Caching at Edge / CDN:
    • CDNs (Cloudflare, Fastly) can cache 404 Not Found and 410 Gone responses for brief periods (e.g., 10 seconds). This protects origin application databases from DDoS or brute-force crawling targeting non-existent IDs.
  2. Circuit Breaker Integration (Resilience4j / Envoy):
    • Circuit breakers calculate failure rates based strictly on 5xx responses (500, 502, 503, 504).
    • Standard client errors (4xx) represent valid rejection of bad client inputs and must never count toward tripping a circuit breaker.
  3. SRE Golden Signals & Alerting:
    • Prometheus metrics tracking http_server_requests_seconds_count{status=~"5.."} trigger automated PagerDuty incidents. Returning 500 for expected business validation issues causes false alarms and disrupts on-call engineering.

4 Tricky Questions

1. What is the fundamental difference between status codes 302 Found and 307 Temporary Redirect?

Answer: Under early HTTP/1.0 specifications, 302 Found was intended as a temporary redirect. However, popular web browsers implemented buggy behavior by converting POST requests into GET upon receiving a 302. To eliminate ambiguity, RFC 9110 defined:

  • 303 See Other: Specifically instructs the client to switch the method to GET for the redirected URI.
  • 307 Temporary Redirect: Guarantees that the client must repeat the redirected request using the exact same HTTP method and body (POST remains POST). This is critical for security in mutating REST workflows.

2. When should an API return 400 Bad Request versus 422 Unprocessable Content?

Answer:

  • 400 Bad Request indicates a syntactic failure: The request was malformed at the protocol or parsing level (e.g., truncated JSON body, invalid character encoding, unparseable headers). The server could not even convert the request into domain objects.
  • 422 Unprocessable Content indicates a semantic failure: The syntax and JSON structure are completely valid, but the data violates domain constraints, schema validations, or business rules (e.g., Bean Validation @NotNull, negative account balances, illegal status transitions).

3. Why must 500 Internal Server Error never be used for expected business rule rejections?

Answer:

  1. Semantic Violation: 5xx codes signal that the server is malfunctioning, buggy, or broken. An expected business rejection (e.g., “Insufficient balance” or “Product out of stock”) is valid application logic handling invalid client actions, which belongs in 4xx (422 or 409).
  2. Infrastructure Impact: Automated SRE monitoring tools, Kubernetes health probes, and Resilience4j circuit breakers treat 5xx errors as system degradation, potentially tripping circuit breakers and generating false PagerDuty alerts.

4. What must a server response with status 401 Unauthorized strictly contain according to RFC 9110?

Answer: According to RFC 9110 Section 15.5.2, an HTTP response with a 401 Unauthorized status must include at least one WWW-Authenticate response header.

  • The header informs the client what authentication scheme and realm are required to access the resource (e.g., WWW-Authenticate: Bearer realm="api.example.com", error="invalid_token").
  • Omitting WWW-Authenticate on a 401 response is a violation of HTTP protocol conformance.

🎯 Interview Cheat Sheet

30-Second Elevator Pitch

HTTP status codes are standardized 3-digit response indicators divided into 5 classes:

  • 1xx: Informational (100 Continue).
  • 2xx: Success: 200 OK, 201 Created (with Location), 202 Accepted (async jobs), 204 No Content (body-less success).
  • 3xx: Redirection: 301/302 (legacy), 303 See Other (PRG pattern), 304 Not Modified (cache hit), 307/308 (strictly preserve method/body).
  • 4xx: Client Errors: 400 (syntax), 401 (unauthenticated, requires WWW-Authenticate), 403 (forbidden), 404 (not found), 409 (conflict), 412 (ETag mismatch), 422 (validation failure), 429 (rate limited).
  • 5xx: Server Errors: 500 (unhandled exception), 502 (bad gateway), 503 (service overloaded), 504 (gateway timeout).

Modern REST services standardize error payloads using RFC 9457 Problem Details.


Red Flags (What NOT to Say)

  • ❌ “401 and 403 are identical synonyms.” (401 = authentication identity missing; 403 = authorization permission denied).
  • ❌ “When an entity is not found by ID, return 500 Internal Server Error.” (Absence of a record is standard client error 404 Not Found).
  • ❌ “Return 200 OK for errors and put the error message inside the JSON body.” (The SOAP/RPC anti-pattern that breaks HTTP caching, proxies, and observability).
  • ❌ “204 No Content returns an empty JSON object {}.” (204 mandates physical absence of a body; Content-Length is 0).