Skip to content
beginner Phase 2 · HTTP Deep Dive

HTTP Status Codes: Complete Reference

Master HTTP status codes across all categories (2xx, 3xx, 4xx, 5xx) with Magento-specific usage examples.

45m
0 problems
Topic Progress 0%

2xx and 3xx Status Codes

2xx Success Codes

The request was successfully received, understood, and accepted.

Code Name When to Use
200 OK Standard success response
201 Created New resource created (POST)
202 Accepted Request accepted for processing (async)
204 No Content Success but no body to return (DELETE)
206 Partial Content Range request (partial download)

200 OK

<?php
// GET request returns 200 with data
http_response_code(200);
header('Content-Type: application/json');
echo json_encode([
    'id' => 1,
    'name' => 'Widget Pro',
    'price' => 29.99
]);

201 Created

<?php
// POST request creates new resource
$product = createProduct($data);

http_response_code(201);
header('Content-Type: application/json');
header('Location: /api/products/' . $product['id']);
echo json_encode($product);

204 No Content

<?php
// DELETE request removes resource
deleteProduct($id);

http_response_code(204);
// No body sent - resource was deleted

3xx Redirection Codes

The client needs to take additional action to complete the request.

Code Name When to Use
301 Moved Permanently URL has changed forever (SEO friendly)
302 Found Temporary redirect (legacy)
303 See Other Redirect after POST (PRG pattern)
304 Not Modified Use cached version
307 Temporary Redirect Temporary redirect, preserve method
308 Permanent Redirect Permanent redirect, preserve method

301 Moved Permanently

<?php
// Force HTTP to HTTPS (permanent)
if (empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off') {
    $url = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: $url");
    exit;
}

// www to non-www redirect
if (substr($_SERVER['HTTP_HOST'], 0, 4) === 'www.') {
    $url = 'https://' . substr($_SERVER['HTTP_HOST'], 4) . $_SERVER['REQUEST_URI'];
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: $url");
    exit;
}

304 Not Modified

<?php
// Cache validation - check if resource has changed
$fileMtime = filemtime('/path/to/resource.js');
$etag = md5_file('/path/to/resource.js');

// Set cache headers
header('Cache-Control: public, max-age=3600');
header('Last-Modified: ' . date('r', $fileMtime));
header('ETag: "' . $etag . '"');

// Check if client has cached version
$ifModifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE'] ?? '';
$ifNoneMatch = $_SERVER['HTTP_IF_NONE_MATCH'] ?? '';

if ($ifModifiedSince === date('r', $fileMtime) || $ifNoneMatch === '"' . $etag . '"') {
    http_response_code(304); // Not Modified
    exit; // No body needed
}

// Send new content
http_response_code(200);
echo file_get_contents('/path/to/resource.js');

4xx Client Error Codes

4xx Client Errors

The request contains bad syntax or cannot be fulfilled by the server.

Code Name When to Use
400 Bad Request Malformed syntax, invalid data
401 Unauthorized Authentication required
403 Forbidden Authenticated but not authorized
404 Not Found Resource doesn't exist
405 Method Not Allowed HTTP method not supported
409 Conflict Resource state conflict
415 Unsupported Media Type Wrong Content-Type
422 Unprocessable Entity Validation errors
429 Too Many Requests Rate limit exceeded

400 Bad Request

<?php
// Invalid JSON body
$rawBody = file_get_contents('php://input');
data = json_decode($rawBody, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    http_response_code(400);
    echo json_encode([
        'error' => 'Bad Request',
        'message' => 'Invalid JSON: ' . json_last_error_msg()
    ]);
    exit;
}

401 Unauthorized vs 403 Forbidden

<?php
// 401 - Not authenticated (no credentials)
function checkAuthentication(): void
{
    $token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';

    if (empty($token)) {
        http_response_code(401);
        header('WWW-Authenticate: Bearer realm="api"');
        echo json_encode(['error' => 'Authentication required']);
        exit;
    }

    $user = validateToken($token);
    if (!$user) {
        http_response_code(401);
        echo json_encode(['error' => 'Invalid token']);
        exit;
    }
}

// 403 - Authenticated but not authorized (no permission)
function checkAuthorization(User $user, string $resource): void
{
    if (!$user->hasPermission($resource)) {
        http_response_code(403);
        echo json_encode(['error' => 'Access denied']);
        exit;
    }
}

404 Not Found

<?php
$product = $productRepository->getById($productId);

if (!$product) {
    http_response_code(404);
    header('Content-Type: application/json');
    echo json_encode([
        'error' => 'Not Found',
        'message' => "Product with ID $productId not found"
    ]);
    exit;
}

422 Unprocessable Entity

<?php
// Validation errors
class Validator
{
    public function validate(array $data): array
    {
        $errors = [];

        if (empty($data['name'])) {
            $errors['name'] = 'Name is required';
        }

        if (!isset($data['price']) || $data['price'] < 0) {
            $errors['price'] = 'Price must be a positive number';
        }

        if (empty($data['sku'])) {
            $errors['sku'] = 'SKU is required';
        } elseif (strlen($data['sku']) > 64) {
            $errors['sku'] = 'SKU must be 64 characters or less';
        }

        return $errors;
    }
}

$validator = new Validator();
$errors = $validator->validate($data);

if (!empty($errors)) {
    http_response_code(422);
    echo json_encode([
        'error' => 'Validation Failed',
        'errors' => $errors
    ]);
    exit;
}

429 Too Many Requests

<?php
function checkRateLimit(string $apiKey): void
{
    $redis = new Redis();
    $redis->connect('127.0.0.1');

    $key = "rate_limit:$apiKey";
    $requests = (int)$redis->get($key);

    if ($requests >= 100) { // 100 requests per hour
        http_response_code(429);
        header('Retry-After: 3600');
        header('X-RateLimit-Limit: 100');
        header('X-RateLimit-Remaining: 0');
        echo json_encode(['error' => 'Rate limit exceeded']);
        exit;
    }

    $redis->incr($key);
    $redis->expire($key, 3600);

    header('X-RateLimit-Limit: 100');
    header('X-RateLimit-Remaining: (100 - $requests - 1)');
}

5xx Server Error Codes and Magento Errors

5xx Server Errors

The server failed to fulfill a valid request.

Code Name When to Use
500 Internal Server Error Generic server error
502 Bad Gateway Upstream server returned invalid response
503 Service Unavailable Server temporarily overloaded/down
504 Gateway Timeout Upstream server too slow

500 Internal Server Error

<?php
// PHP error handling for production
set_error_handler(function ($severity, $message, $file, $line) {
    throw new \ErrorException($message, 0, $severity, $file, $line);
});

set_exception_handler(function (\Throwable $e) {
    error_log($e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());

    http_response_code(500);
    header('Content-Type: application/json');

    // Don't expose internal details in production
    echo json_encode([
        'error' => 'Internal Server Error',
        'message' => 'An unexpected error occurred'
    ]);
});

register_shutdown_function(function () {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR])) {
        http_response_code(500);
        echo json_encode(['error' => 'Fatal error occurred']);
    }
});

503 Service Unavailable

<?php
// Check if maintenance mode is active
function isMaintenanceMode(): bool
Maintenance flag file
if (file_exists('/var/.maintenance.flag')) {
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    $allowed = json_decode(file_get_contents('/var/.maintenance.ip'), true) ?? [];

    // Allow specific IPs during maintenance
    if (in_array($ip, $allowed)) {
        return false;
    }

    return true;
}

return false;
}

if (isMaintenanceMode()) {
    http_response_code(503);
    header('Retry-After: 3600'); // Try again in 1 hour
    echo json_encode([
        'error' => 'Service Unavailable',
        'message' => 'System is under maintenance'
    ]);
    exit;
}

Magento Common Error Codes

Code Magento Component Typical Cause
400 Web API Invalid request body, missing required fields
401 Web API Missing or invalid API token
403 Admin Insufficient permissions
404 Frontend Product/category not found, wrong URL
422 Web API Validation failure (invalid SKU, price format)
500 Application PHP error, module conflict, compilation error
503 Varnish/Nginx Backend server down, maintenance mode

Error Response Best Practices

<?php
// Standardized error response format
class ErrorResponse
{
    public static function json(int $code, string $message, array $details = []): void
    {
        http_response_code($code);
        header('Content-Type: application/json');

        $response = [
            'error' => [
                'code' => $code,
                'message' => $message,
                'timestamp' => date('c'),
                'request_id' => uniqid('req_')
            ]
        ];

        if (!empty($details)) {
            $response['error']['details'] = $details;
        }

        echo json_encode($response);
    }
}

// Usage
ErrorResponse::json(422, 'Validation failed', [
    'field' => 'price',
    'message' => 'Price must be greater than 0'
]);

Key Takeaway

Always use the most specific status code available. 422 is better than 400 for validation errors. 404 is better than 400 when a resource doesn't exist. Proper status codes help clients understand what happened and how to proceed.

Quiz

1. What status code should you return when a product is not found?

Question 1 options

2. What is the difference between 401 and 403?

Question 2 options

3. Which status code should be returned after successfully creating a new product with POST?

Question 3 options

4. What does 429 Too Many Requests indicate?

Question 4 options

5. What is 304 Not Modified used for?

Question 5 options

Flashcards

Question

What are the 5 HTTP status code categories?

Answer

1xx (Informational), 2xx (Success), 3xx (Redirection), 4xx (Client Error), 5xx (Server Error)

Question

When do you use 201 vs 200?

Answer

201 Created: POST request that created a new resource. 200 OK: GET request or successful operation that doesn't create a new resource.

Question

When do you use 401 vs 403?

Answer

401: Client hasn't provided credentials (not authenticated). 403: Client is authenticated but lacks permission (not authorized).

Question

What status code is used for maintenance mode?

Answer

503 Service Unavailable. Include a Retry-After header to tell clients when to retry.

Question

What is 422 Unprocessable Entity used for?

Answer

Validation errors - when the request syntax is correct but the data fails business validation (invalid email, negative price, missing required fields).

Question

What does 304 Not Modified do?

Answer

Tells the client the resource hasn't changed. The client can use its cached copy without downloading the resource again. Used with ETag and If-Modified-Since headers.

Question

What status code should a DELETE request return on success?

Answer

204 No Content - the resource was successfully deleted and there's no response body to return.

Question

What does 502 Bad Gateway mean?

Answer

The server received an invalid response from an upstream server (like PHP-FPM returning invalid data to Nginx). Common when backend processes crash.

Revision Notes

Key Takeaways

  • 1. 2xx codes indicate success: 200 (OK), 201 (Created), 204 (No Content)
  • 2. 3xx codes handle redirects: 301 (Permanent), 304 (Not Modified), 307 (Temporary)
  • 3. 4xx codes indicate client errors: 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found)
  • 4. 5xx codes indicate server errors: 500 (Internal), 503 (Unavailable)
  • 5. 422 (Unprocessable Entity) is ideal for validation errors
  • 6. 429 (Too Many Requests) is used for rate limiting
  • 7. Always use the most specific status code available

Interview Tips

  • Know the difference between 401 and 403 (authentication vs authorization)
  • Understand when to use 201 vs 200 for creation responses
  • Explain the purpose of 304 Not Modified and ETag caching
  • Know Magento's common error codes and their causes
  • Describe best practices for error response formats

Cheat Sheet

HTTP Status Codes Cheat Sheet

2xx Success:

  • 200 OK - Standard success
  • 201 Created - Resource created (POST)
  • 204 No Content - Success, no body (DELETE)

3xx Redirection:

  • 301 Moved Permanently - URL changed forever
  • 304 Not Modified - Use cached version
  • 307 Temporary Redirect - Temporary, preserve method

4xx Client Error:

  • 400 Bad Request - Malformed syntax
  • 401 Unauthorized - Not authenticated
  • 403 Forbidden - Not authorized
  • 404 Not Found - Resource doesn't exist
  • 405 Method Not Allowed - Invalid HTTP method
  • 422 Unprocessable Entity - Validation error
  • 429 Too Many Requests - Rate limit exceeded

5xx Server Error:

  • 500 Internal Server Error - Generic server error
  • 502 Bad Gateway - Invalid upstream response
  • 503 Service Unavailable - Server overloaded/maintenance
  • 504 Gateway Timeout - Upstream too slow