HTTP Protocol & Methods

The language of the web

← Back to Index

What is HTTP?

HTTP (HyperText Transfer Protocol) is the foundation of the World Wide Web and the protocol that makes the internet work as we know it. Every time you visit a website, check your email through a web browser, stream a video, or use a mobile app that connects to the internet, HTTP is working behind the scenes.

HTTP defines how messages are formatted and transmitted, and what actions web servers and browsers should take in response to various commands. It's the "language" that clients (like your browser) and servers speak to each other.

A Simple Analogy: The Postal System

Understanding HTTP becomes easier when you compare it to sending letters:

HTTP (HyperText Transfer Protocol) is the application-layer protocol for transmitting hypermedia documents (like HTML). Its key characteristics:

  • Request-Response Model: Communication is always initiated by the client. The server waits for requests and sends responses.
  • Stateless: Each request is completely independent. The server doesn't remember previous requests (though we can add state with sessions and cookies).
  • Text-based (HTTP/1.x): Requests and responses are human-readable plain text, making debugging easier.
  • Extensible: Headers can carry custom metadata, allowing protocols to be built on top of HTTP.
  • Port 80 (HTTP) / Port 443 (HTTPS): These are the default ports, though any port can be used.

A Brief History of HTTP

Understanding HTTP's evolution helps explain why things work the way they do today:

As a Java developer, you'll primarily work with HTTP/1.1 concepts, but the principles apply across versions.

// HTTP communication flow

Client                                      Server
   │                                           │
   │   ─────── HTTP Request ──────────▶       │
   │   GET /api/users HTTP/1.1                │
   │   Host: api.example.com                  │
   │                                           │
   │   ◀────── HTTP Response ─────────        │
   │   HTTP/1.1 200 OK                        │
   │   Content-Type: application/json         │
   │   {"users": [...]}                       │
   │                                           │

HTTP Request Structure

// Complete HTTP Request breakdown

┌─────────────────────────────────────────────────────────────┐
│ REQUEST LINE                                                │
│ GET /api/products/123?include=reviews HTTP/1.1              │
│ ─── ─────────────────────────────────── ────────            │
│  │           │                             │                 │
│ Method     Path + Query                 Version              │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ HEADERS                                                     │
│ Host: api.example.com                                       │
│ Accept: application/json                                    │
│ Authorization: Bearer eyJhbGciOiJIUzI1NiIs...              │
│ Content-Type: application/json                              │
│ User-Agent: Mozilla/5.0                                     │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ BODY (optional, for POST/PUT/PATCH)                        │
│ {                                                           │
│     "name": "New Product",                                  │
│     "price": 29.99                                          │
│ }                                                           │
└─────────────────────────────────────────────────────────────┘

Reading Request in Java (Spring)

@PostMapping("/api/products")
public Product createProduct(
    // Request body - automatically parsed from JSON
    @RequestBody Product product,

    // Path variable - from URL
    @PathVariable("id") Long id,

    // Query parameter - ?category=electronics
    @RequestParam("category") String category,

    // Header value
    @RequestHeader("Authorization") String authHeader,

    // Full request access
    HttpServletRequest request
) {
    // Access any part of the request
    String method = request.getMethod();        // "POST"
    String uri = request.getRequestURI();       // "/api/products"
    String query = request.getQueryString();    // "category=electronics"

    return productService.create(product);
}

HTTP Methods (Verbs)

Method Purpose Has Body Idempotent Safe
GET Retrieve data No Yes Yes
POST Create resource Yes No No
PUT Replace resource Yes Yes No
PATCH Partial update Yes No* No
DELETE Remove resource No Yes No
HEAD GET without body No Yes Yes
OPTIONS Get allowed methods No Yes Yes
Key Terms
  • Idempotent: Same request multiple times = same result
  • Safe: Doesn't modify data (read-only)

GET - Retrieve Data

// GET requests retrieve data - never modify anything!

// Request
GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json

// Java handler
@GetMapping("/api/users/{id}")
public User getUser(@PathVariable Long id) {
    return userService.findById(id);
}

// GET with query parameters
GET /api/users?page=1&size=10&sort=name HTTP/1.1

@GetMapping("/api/users")
public Page<User> getUsers(
    @RequestParam(defaultValue = "0") int page,
    @RequestParam(defaultValue = "10") int size,
    @RequestParam(defaultValue = "id") String sort
) {
    return userService.findAll(PageRequest.of(page, size, Sort.by(sort)));
}

POST - Create Resource

// POST creates new resources

// Request
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
    "name": "John Doe",
    "email": "john@example.com"
}

// Java handler
@PostMapping("/api/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
    User created = userService.create(user);
    URI location = URI.create("/api/users/" + created.getId());

    return ResponseEntity
        .created(location)     // 201 Created
        .body(created);
}

PUT - Replace Resource

// PUT replaces entire resource (send all fields)

// Request
PUT /api/users/123 HTTP/1.1
Content-Type: application/json

{
    "name": "John Updated",
    "email": "john.new@example.com",
    "phone": "555-1234"
}

// Java handler
@PutMapping("/api/users/{id}")
public User replaceUser(
    @PathVariable Long id,
    @RequestBody User user
) {
    // Replace ALL fields
    return userService.replace(id, user);
}

PATCH - Partial Update

// PATCH updates only specified fields

// Request - only updating email
PATCH /api/users/123 HTTP/1.1
Content-Type: application/json

{
    "email": "new.email@example.com"
}

// Java handler
@PatchMapping("/api/users/{id}")
public User updateUser(
    @PathVariable Long id,
    @RequestBody Map<String, Object> updates
) {
    // Update only provided fields
    return userService.partialUpdate(id, updates);
}

DELETE - Remove Resource

// DELETE removes resources

// Request
DELETE /api/users/123 HTTP/1.1
Host: api.example.com

// Java handler
@DeleteMapping("/api/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    userService.delete(id);
    return ResponseEntity.noContent().build();  // 204 No Content
}

HTTP Status Codes

1xx - Informational

// Rarely used directly
100 Continue           // Server received headers, send body
101 Switching Protocols// Upgrading to WebSocket

2xx - Success

// Request succeeded
200 OK                 // Standard success (GET, PUT, PATCH)
201 Created            // Resource created (POST)
204 No Content         // Success, no body (DELETE)
202 Accepted           // Processing started (async operations)

// Java examples
return ResponseEntity.ok(user);                     // 200
return ResponseEntity.created(location).body(user); // 201
return ResponseEntity.noContent().build();          // 204
return ResponseEntity.accepted().build();           // 202

3xx - Redirection

// Resource moved
301 Moved Permanently  // URL changed forever
302 Found              // Temporary redirect
304 Not Modified       // Use cached version
307 Temporary Redirect // Redirect, keep method
308 Permanent Redirect // Permanent, keep method

// Java redirect
return ResponseEntity
    .status(HttpStatus.MOVED_PERMANENTLY)
    .location(URI.create("/new-url"))
    .build();

4xx - Client Errors

// Client did something wrong
400 Bad Request        // Invalid syntax, validation error
401 Unauthorized       // Not authenticated (login required)
403 Forbidden          // Authenticated but not allowed
404 Not Found          // Resource doesn't exist
405 Method Not Allowed // GET when only POST allowed
409 Conflict           // Conflict with current state
422 Unprocessable      // Valid syntax but invalid data
429 Too Many Requests  // Rate limited

// Java exception handling
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<?> handleNotFound(NotFoundException e) {
    return ResponseEntity.notFound().build();  // 404
}

@ExceptionHandler(ValidationException.class)
public ResponseEntity<?> handleValidation(ValidationException e) {
    return ResponseEntity.badRequest().body(e.getMessage());  // 400
}

5xx - Server Errors

// Server did something wrong
500 Internal Server Error  // Generic server error
501 Not Implemented        // Feature not supported
502 Bad Gateway            // Upstream server error
503 Service Unavailable    // Server overloaded/maintenance
504 Gateway Timeout        // Upstream server timeout

// Java - let Spring handle 500s for unhandled exceptions
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleGeneric(Exception e) {
    log.error("Unexpected error", e);
    return ResponseEntity
        .status(HttpStatus.INTERNAL_SERVER_ERROR)
        .body("An unexpected error occurred");
}

Common HTTP Headers

Request Headers

// Headers the client sends

Accept: application/json           // I want JSON response
Accept-Language: en-US             // Preferred language
Authorization: Bearer eyJ...       // Authentication token
Content-Type: application/json     // Body format I'm sending
Cookie: sessionId=abc123           // Send cookies
User-Agent: Mozilla/5.0...         // Browser/client info
Origin: https://example.com        // Where request came from
Cache-Control: no-cache            // Caching preferences

Response Headers

// Headers the server sends

Content-Type: application/json     // Response body format
Content-Length: 1234               // Body size in bytes
Set-Cookie: sessionId=abc123       // Store this cookie
Location: /api/users/456           // Redirect URL (201, 3xx)
Cache-Control: max-age=3600        // Cache for 1 hour
Access-Control-Allow-Origin: *     // CORS header
WWW-Authenticate: Bearer           // Auth method (401)

// Setting headers in Java
@GetMapping("/api/report")
public ResponseEntity<byte[]> downloadReport() {
    byte[] pdf = reportService.generatePdf();

    return ResponseEntity.ok()
        .header(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=report.pdf")
        .contentType(MediaType.APPLICATION_PDF)
        .contentLength(pdf.length)
        .body(pdf);
}

HTTP vs HTTPS

Aspect HTTP HTTPS
Port 80 443
Encryption None (plaintext) TLS/SSL encrypted
Security Can be intercepted Secure communication
Certificate Not required Required
Use case Development only Production (always!)
// Spring Boot HTTPS configuration
// application.properties

server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12

// Redirect HTTP to HTTPS
@Configuration
public class HttpsRedirectConfig {
    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(httpConnector());
        return tomcat;
    }
}

HTTP/1.1 vs HTTP/2 vs HTTP/3

Feature HTTP/1.1 HTTP/2 HTTP/3
Connections One request per connection Multiplexed Multiplexed
Format Text Binary Binary
Transport TCP TCP QUIC (UDP)
Header compression No HPACK QPACK
Server push No Yes Yes
// Most Java servers support HTTP/2 automatically
// Spring Boot with HTTP/2

// application.properties
server.http2.enabled=true

// Note: HTTP/2 typically requires HTTPS

Testing HTTP with Tools

# curl - Command line HTTP client

# GET request
curl https://api.example.com/users

# GET with headers
curl -H "Authorization: Bearer token123" \
     -H "Accept: application/json" \
     https://api.example.com/users

# POST with JSON body
curl -X POST \
     -H "Content-Type: application/json" \
     -d '{"name": "John", "email": "john@example.com"}' \
     https://api.example.com/users

# See response headers
curl -i https://api.example.com/users

# Verbose mode (debug)
curl -v https://api.example.com/users

# PUT request
curl -X PUT \
     -H "Content-Type: application/json" \
     -d '{"name": "John Updated"}' \
     https://api.example.com/users/123

# DELETE request
curl -X DELETE https://api.example.com/users/123

Summary

  • HTTP: Protocol for client-server communication
  • Methods: GET (read), POST (create), PUT (replace), PATCH (update), DELETE (remove)
  • Status codes: 2xx success, 4xx client error, 5xx server error
  • Headers: Metadata about the request/response
  • HTTPS: Always use in production (encrypted)
  • Stateless: Each request is independent