HTTP methods (also called HTTP verbs) tell the server what action you want to perform on a resource. This beginner-friendly guide explains each method with real-world analogies and practical examples.
Table of Contents
- What Are HTTP Methods?
- GET - Retrieve Data
- POST - Create New Data
- PUT - Update/Replace Data
- PATCH - Partial Update
- DELETE - Remove Data
- Other HTTP Methods
- Method Comparison
What Are HTTP Methods?
HTTP methods are like verbs in a sentence - they tell the server what action you want to take. When you visit a website or use an app, your device sends HTTP requests with specific methods.
Simple Analogy: Think of HTTP methods like actions in a library:
- GET = Read a book (don't take it home)
- POST = Add a new book to the library
- PUT = Replace an entire book with a new edition
- PATCH = Fix typos in a book's pages
- DELETE = Remove a book from the library
The Main HTTP Methods
| method | action | example | changes |
|---|---|---|---|
| GET | Read/Retrieve | View a webpage | No |
| POST | Create | Submit a form | Yes |
| PUT | Update/Replace | Update profile | Yes |
| PATCH | Partial Update | Change email | Yes |
| DELETE | Remove | Delete account | Yes |
Important Properties
Safe: Doesn't change anything on the server (read-only)
Idempotent: Same result if called once or multiple times
Cacheable: Response can be stored for future use
SAFE? IDEMPOTENT? CACHEABLE?
GET ✅ Yes ✅ Yes ✅ Yes
POST ❌ No ❌ No 🟡 Rarely
PUT ❌ No ✅ Yes ❌ No
PATCH ❌ No ❌ No ❌ No
DELETE ❌ No ✅ Yes ❌ No
GET - Retrieve Data
Purpose: Read or retrieve data from the server. Never modifies anything.
Real-World Analogies
- 📖 Reading a book in a library (don't take it home)
- 👀 Looking at a menu (doesn't order food)
- 🔍 Searching Google (just viewing results)
- 📺 Watching a YouTube video (just viewing)
When to Use GET
✅ Viewing a webpage
✅ Loading user profile data
✅ Searching for products
✅ Getting a list of items
✅ Downloading a file
✅ Checking status
Basic GET Request
// Simple GET request
fetch('https://api.example.com/users/123')
.then(response => response.json())
.then(user => console.log(user));
// Output:
// {
// "id": 123,
// "name": "John Doe",
// "email": "john@example.com"
// }
GET with Query Parameters
// Search for users with filters
fetch('https://api.example.com/users?role=admin&country=US&limit=10')
.then(response => response.json())
.then(users => console.log(users));
// The URL breaks down as:
// Base: https://api.example.com/users
// Parameters: ?role=admin&country=US&limit=10
GET in HTML
<!-- Every link is a GET request -->
<a href="/about">About Us</a>
<!-- Images are GET requests -->
<img src="/logo.png" alt="Logo">
<!-- Stylesheets are GET requests -->
<link rel="stylesheet" href="/styles.css">
<!-- Scripts are GET requests -->
<script src="/app.js"></script>
<!-- Forms with GET (don't use for sensitive data!) -->
<form action="/search" method="GET">
<input type="text" name="q" placeholder="Search...">
<button>Search</button>
</form>
<!-- Submits to: /search?q=your+search+term -->
GET Best Practices
// ✅ GOOD - Use GET for reading data
fetch('/api/users/123')
// ✅ GOOD - Use query parameters for filters
fetch('/api/products?category=electronics&maxPrice=1000')
// ❌ BAD - Don't send sensitive data in URL
fetch('/api/login?password=secret123') // Password visible in URL!
// ❌ BAD - Don't use GET to modify data
fetch('/api/users/123/delete') // Should use DELETE method
Security Note: GET requests are visible in browser history, logs, and can be cached. Never send passwords or sensitive data via GET. Use POST instead.
POST - Create New Data
Purpose: Create a new resource on the server. Sends data in the request body.
Real-World Analogies
- ✍️ Filling out a signup form
- 📝 Writing a new blog post
- 💳 Placing an order
- 📤 Uploading a photo
- 💬 Posting a comment
When to Use POST
✅ Creating a new user account
✅ Submitting a contact form
✅ Posting a comment
✅ Uploading a file
✅ Placing an order
✅ Logging in (sending credentials)
Basic POST Request
// Create a new user
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Jane Smith',
email: 'jane@example.com',
password: 'securepass123'
})
})
.then(response => response.json())
.then(newUser => console.log('Created:', newUser));
// Response (201 Created):
// {
// "id": 124,
// "name": "Jane Smith",
// "email": "jane@example.com",
// "createdAt": "2025-01-15T10:30:00Z"
// }
POST with Form Data
// Upload a file with form data
const formData = new FormData();
formData.append('name', 'Profile Picture');
formData.append('file', fileInput.files[0]);
fetch('https://api.example.com/upload', {
method: 'POST',
body: formData // Don't set Content-Type - browser does it
})
.then(response => response.json())
.then(result => console.log('Uploaded:', result));
POST in HTML Forms
<!-- Traditional form POST -->
<form action="/api/contact" method="POST">
<input type="text" name="name" placeholder="Your name" required>
<input type="email" name="email" placeholder="Email" required>
<textarea name="message" placeholder="Message" required></textarea>
<button type="submit">Send</button>
</form>
<!-- File upload form -->
<form action="/api/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="avatar" accept="image/*">
<button type="submit">Upload</button>
</form>
POST Best Practices
// ✅ GOOD - Use POST to create resources
fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'John' })
})
// ✅ GOOD - Use POST for sensitive data (login)
fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ email, password })
})
// ✅ GOOD - Set proper Content-Type
headers: {
'Content-Type': 'application/json'
}
// ❌ BAD - Don't use POST to retrieve data
fetch('/api/users/123', { method: 'POST' }) // Should use GET
POST vs GET: Use POST when you're creating something new or sending sensitive data. Use GET when you're just reading/viewing data.
PUT - Update/Replace Data
Purpose: Update an entire resource, replacing all fields. If the resource doesn't exist, it may create it.
Real-World Analogies
- 📝 Rewriting an entire document from scratch
- 🏠 Replacing an entire house (not just renovating)
- 📋 Overwriting a file completely
- 🎨 Replacing a painting with a new one
When to Use PUT
✅ Updating all fields of a user profile
✅ Replacing entire configuration
✅ Overwriting a document
✅ Updating complete settings
Basic PUT Request
// Update user - replaces ALL fields
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({
name: 'John Updated',
email: 'john.new@example.com',
bio: 'Updated bio',
location: 'New York'
})
})
.then(response => response.json())
.then(user => console.log('Updated:', user));
// Important: All fields must be included!
// Any field not included will be removed or set to null
PUT vs POST Example
// POST - Create new resource (URL doesn't include ID)
POST /api/users
Body: { name: "John", email: "john@example.com" }
Result: Creates user with ID 123
// PUT - Update existing resource (URL includes ID)
PUT /api/users/123
Body: { name: "John Updated", email: "john.new@example.com" }
Result: Updates user 123 completely
Idempotent Nature of PUT
// PUT is idempotent - calling it multiple times has same result
// Call 1:
PUT /api/users/123
Body: { name: "John", email: "john@example.com" }
Result: User 123 = { name: "John", email: "john@example.com" }
// Call 2: (exact same request)
PUT /api/users/123
Body: { name: "John", email: "john@example.com" }
Result: User 123 = { name: "John", email: "john@example.com" } (same!)
// No duplicate users created, same end result
PUT Best Practices
// ✅ GOOD - Send complete object
fetch('/api/users/123', {
method: 'PUT',
body: JSON.stringify({
name: 'John',
email: 'john@example.com',
bio: 'Developer',
location: 'NYC'
})
})
// ❌ BAD - Missing fields (they'll be deleted!)
fetch('/api/users/123', {
method: 'PUT',
body: JSON.stringify({
email: 'john@example.com' // Where's name, bio, location?
})
})
// Result: User loses name, bio, and location!
// 💡 BETTER - Use PATCH for partial updates
fetch('/api/users/123', {
method: 'PATCH',
body: JSON.stringify({
email: 'john@example.com' // Only update email
})
})
PATCH - Partial Update
Purpose: Update only specific fields of a resource without replacing the entire thing.
Real-World Analogies
- 🔧 Fixing a typo in a document (not rewriting it)
- 🏠 Renovating one room (not rebuilding the house)
- 🎨 Touching up part of a painting
- ✏️ Editing just one section of a book
When to Use PATCH
✅ Updating just the email address
✅ Changing only the password
✅ Toggling a single setting
✅ Updating specific fields
✅ Incrementing a counter
Basic PATCH Request
// Update only the email (keep everything else)
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({
email: 'john.new@example.com'
})
})
.then(response => response.json())
.then(user => console.log('Patched:', user));
// Response:
// {
// "id": 123,
// "name": "John Doe", ← Unchanged
// "email": "john.new@example.com", ← Updated
// "bio": "Developer", ← Unchanged
// "location": "NYC" ← Unchanged
// }
PUT vs PATCH Comparison
// Original user:
{
"id": 123,
"name": "John Doe",
"email": "john@example.com",
"bio": "Developer",
"location": "NYC"
}
// ========================================
// Using PUT - Must send ALL fields
// ========================================
PUT /api/users/123
Body: {
"name": "John Doe",
"email": "john.new@example.com", // Changed
"bio": "Developer",
"location": "NYC"
}
Result: Email updated ✅, but had to send everything
// ========================================
// Using PATCH - Send only what changed
// ========================================
PATCH /api/users/123
Body: {
"email": "john.new@example.com" // Only this
}
Result: Email updated ✅, cleaner code!
Multiple Field Updates
// Update multiple fields at once
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
body: JSON.stringify({
bio: 'Senior Developer',
location: 'San Francisco'
})
})
// Only bio and location change, name and email stay the same
Common PATCH Use Cases
// Toggle a setting
PATCH /api/users/123
Body: { emailNotifications: false }
// Increment a counter
PATCH /api/posts/456
Body: { views: { $increment: 1 } }
// Add to a list
PATCH /api/users/123
Body: { interests: { $push: "photography" } }
// Change password
PATCH /api/users/123
Body: { password: "newSecurePassword123" }
// Update last login time
PATCH /api/users/123
Body: { lastLoginAt: "2025-01-15T10:30:00Z" }
When to use PATCH vs PUT:
- Use PATCH when updating 1-2 fields (most common)
- Use PUT when replacing the entire resource
- In doubt? Use PATCH - it's safer and more efficient
DELETE - Remove Data
Purpose: Delete a resource from the server permanently.
Real-World Analogies
- 🗑️ Deleting a file from your computer
- 📚 Removing a book from the library
- 🛒 Removing an item from shopping cart
- 👤 Deleting your account
- 💬 Deleting a comment
When to Use DELETE
✅ Deleting a user account
✅ Removing a post or comment
✅ Clearing shopping cart
✅ Unsubscribing from a service
✅ Removing a file
Basic DELETE Request
// Delete a user
fetch('https://api.example.com/users/123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer your-token'
}
})
.then(response => {
if (response.status === 204) {
console.log('User deleted successfully');
}
});
// Common responses:
// 204 No Content - Deleted, no body returned
// 200 OK - Deleted, with confirmation body
// 404 Not Found - Already deleted or doesn't exist
// 403 Forbidden - No permission to delete
DELETE with Confirmation
// Delete with confirmation in response
fetch('https://api.example.com/posts/456', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer your-token'
}
})
.then(response => response.json())
.then(result => console.log(result));
// Response (200 OK):
// {
// "message": "Post deleted successfully",
// "deletedId": 456,
// "deletedAt": "2025-01-15T10:30:00Z"
// }
Soft Delete vs Hard Delete
// HARD DELETE - Permanently removes from database
DELETE /api/users/123
→ User completely removed from database
// SOFT DELETE - Marks as deleted but keeps data
PATCH /api/users/123
Body: { deleted: true, deletedAt: "2025-01-15T10:30:00Z" }
→ User still in database but marked as deleted
// Why soft delete?
// - Can recover deleted data
// - Keep records for compliance
// - Maintain referential integrity
// - Analyze deletion patterns
Delete All vs Delete One
// Delete specific item (common)
DELETE /api/users/123
→ Deletes user 123
// Delete with filter (less common, use carefully!)
DELETE /api/posts?author=123
→ Deletes all posts by author 123
// Bulk delete (usually POST with list)
POST /api/users/bulk-delete
Body: { userIds: [123, 124, 125] }
→ Safer for multiple deletions
DELETE Best Practices
// ✅ GOOD - Require authentication
headers: {
'Authorization': 'Bearer your-token'
}
// ✅ GOOD - Confirm before deletion
if (confirm('Are you sure you want to delete your account?')) {
fetch('/api/users/123', { method: 'DELETE' });
}
// ✅ GOOD - Handle errors gracefully
try {
const response = await fetch('/api/users/123', { method: 'DELETE' });
if (!response.ok) throw new Error('Failed to delete');
console.log('Deleted successfully');
} catch (error) {
alert('Error deleting user. Please try again.');
}
// ❌ BAD - No confirmation for destructive action
fetch('/api/users/123', { method: 'DELETE' }); // Instant delete!
// ❌ BAD - Using GET to delete
fetch('/api/users/123/delete') // Should use DELETE method
Caution: DELETE operations are usually irreversible. Always:
- Require user confirmation
- Implement proper authentication
- Consider soft deletes for important data
- Log deletion events for audit trails
Other HTTP Methods
HEAD - Get Headers Only
Like GET but returns only headers, no body. Useful for checking if resource exists.
// Check if file exists without downloading it
fetch('https://api.example.com/large-file.zip', {
method: 'HEAD'
})
.then(response => {
console.log('Content-Length:', response.headers.get('Content-Length'));
console.log('Last-Modified:', response.headers.get('Last-Modified'));
console.log('Exists:', response.ok);
});
// Use cases:
// - Check file size before downloading
// - Verify resource exists
// - Check last modified date
// - Check if URL is valid
OPTIONS - Get Available Methods
Returns which HTTP methods are allowed for a resource.
// Find out what methods are supported
fetch('https://api.example.com/users/123', {
method: 'OPTIONS'
})
.then(response => {
console.log('Allowed:', response.headers.get('Allow'));
});
// Response:
// Allow: GET, POST, PUT, PATCH, DELETE, OPTIONS
// Mainly used for:
// - CORS preflight requests (automatic)
// - API discovery
// - Checking permissions
CONNECT, TRACE - Rarely Used
CONNECT: Establishes a tunnel (used for HTTPS proxies)
TRACE: Echoes request back (mostly disabled for security)
These are rarely used in typical web development:
CONNECT - Used by proxies for SSL tunneling
TRACE - Debugging tool (usually disabled)
You'll likely never need these in normal API development.
Method Comparison
Complete Comparison Table
Method Purpose Safe? Idempotent? Has Body? Use Case
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GET Read ✅ ✅ ❌ View page/data
POST Create ❌ ❌ ✅ Submit form
PUT Replace all ❌ ✅ ✅ Update profile
PATCH Update partial ❌ ❌ ✅ Change email
DELETE Remove ❌ ✅ ❌ Delete account
HEAD Get headers ✅ ✅ ❌ Check if exists
OPTIONS Get methods ✅ ✅ ❌ CORS preflight
Decision Tree: Which Method to Use?
Are you READING data?
└─ YES → Use GET
└─ NO ↓
Are you CREATING something new?
└─ YES → Use POST
└─ NO ↓
Are you DELETING something?
└─ YES → Use DELETE
└─ NO ↓
Are you UPDATING existing data?
├─ Updating ALL fields? → Use PUT
└─ Updating SOME fields? → Use PATCH
Common Patterns
// CRUD Operations (Create, Read, Update, Delete)
// CREATE - POST
POST /api/users → Create new user
// READ - GET
GET /api/users → List all users
GET /api/users/123 → Get user 123
// UPDATE - PUT or PATCH
PUT /api/users/123 → Replace user 123
PATCH /api/users/123 → Update user 123 partially
// DELETE - DELETE
DELETE /api/users/123 → Delete user 123
Real-World Example: Blog Application
// Blog Posts API
// View all posts
GET /api/posts
GET /api/posts?category=tech&limit=10
// View single post
GET /api/posts/123
// Create new post
POST /api/posts
Body: { title: "My Post", content: "..." }
// Update entire post
PUT /api/posts/123
Body: { title: "Updated", content: "...", tags: [...] }
// Update post title only
PATCH /api/posts/123
Body: { title: "New Title" }
// Delete post
DELETE /api/posts/123
// Comments on a post
GET /api/posts/123/comments → List comments
POST /api/posts/123/comments → Add comment
DELETE /api/posts/123/comments/456 → Delete comment
Summary
HTTP methods are fundamental to how the web works. Understanding when to use each method is crucial for building and consuming APIs effectively.
Key Takeaways:
✅ GET - Read data (safe, cacheable)
✅ POST - Create new data (not idempotent)
✅ PUT - Replace entire resource (idempotent)
✅ PATCH - Update specific fields (more common than PUT)
✅ DELETE - Remove data (idempotent)
✅ Use proper methods for semantic clarity
✅ Never use GET for sensitive data
✅ Always use HTTPS for security
Quick Rules:
- Reading? → GET
- Creating? → POST
- Updating everything? → PUT
- Updating some fields? → PATCH
- Deleting? → DELETE