NANDHOO.

HTTP Methods: GET, POST & More

HTTP Methods: GET, POST & More


HTTP methods (also called verbs) tell the server what kind of operation you want to perform on a resource. Choosing the right method makes your API predictable, maintainable, and aligned with REST conventions.




1. The Complete Set of HTTP Methods


MethodPurposeBody?Safe?Idempotent?Cacheable?
GETRetrieve a resourceNo
HEADRetrieve headers only (no body)No
POSTCreate a new resource / trigger an actionYesSometimes
PUTReplace a resource entirelyYes
PATCHPartially update a resourceYes
DELETERemove a resourceOptional
OPTIONSAsk what methods are supportedNo
CONNECTOpen a tunnel (used for HTTPS proxies)No
TRACEEcho the request (debugging, mostly disabled)No

Key Properties Explained


  • Safe: Does not alter server state. A safe method should only read data, never write it.
  • Idempotent: Calling the same operation multiple times produces the same result as calling it once. DELETE /users/42 twice — the user is still gone after both calls.
  • Cacheable: The response can be stored and reused for future equivalent requests.



2. GET — Retrieving Data


GET is the most common HTTP method. Every time you visit a web page, your browser sends a GET request.


Rules for GET

  • Never change server state — GET must be a pure read
  • No request body (browsers ignore it; some servers reject it)
  • Always cacheable — browsers and CDNs can store GET responses
  • Query parameters go in the URL: /users?sort=name&page=2

// Simple GET
const response = await fetch('/api/courses');
const courses  = await response.json();

// GET with query parameters const params = new URLSearchParams({ level: 'beginner', sort: 'title', page: '1' }); const response = await fetch(/api/courses?${params}); const courses = await response.json();


// GET a specific resource by ID const response = await fetch('/api/courses/42'); const course = await response.json();


Raw GET request:

GET /api/courses?level=beginner&page=1 HTTP/1.1
Host: api.nandhoo.com
Accept: application/json
Authorization: Bearer eyJhbG...

Expected response:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=60

[{ "id": 1, "title": "HTML5", ... }, ...]




3. POST — Creating Resources


POST sends data to the server to create a new resource or trigger an action (like sending an email, running a batch job, or logging in).


Rules for POST

  • Has a request body with the data to create
  • The server decides the new resource's URL (usually returned in the Location header)
  • Not idempotent — clicking "submit" twice may create two records
  • Response is usually 201 Created with the new resource in the body

// Create a new user account
const response = await fetch('/api/users', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'AliceCodes',
    email:    'alice@example.com',
    password: 'secure-hashed-server-side'
  })
});

// 201 Created response includes the new resource const newUser = await response.json(); console.log('Created:', newUser.id); console.log('Find at:', response.headers.get('Location')); // /api/users/99


Raw POST request:

POST /api/users HTTP/1.1
Host: api.nandhoo.com
Content-Type: application/json
Content-Length: 68

{"username":"AliceCodes","email":"alice@example.com"}


Expected response:

HTTP/1.1 201 Created
Location: /api/users/99
Content-Type: application/json

{"id":99,"username":"AliceCodes","createdAt":"2025-03-31T07:38:00Z"}




4. PUT — Replacing a Resource Completely


PUT replaces the entire resource at a given URL with the data in the request body. Fields not included in the body are deleted or reset to defaults.


// Replace the entire user profile
const response = await fetch('/api/users/99', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'AliceCodes',
    email:    'alice-new@example.com',
    level:    'intermediate',
    bio:      'I love coding!'
    // ⚠️ All fields must be provided — omitted fields will be cleared
  })
});

If idempotent — sending the same PUT twice results in the same server state.




5. PATCH — Partial Updates


PATCH updates only the specified fields of a resource, leaving everything else unchanged.


// Only update the email — everything else stays the same
const response = await fetch('/api/users/99', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'alice-patched@example.com'
    // username, level, bio are untouched
  })
});

PUT vs PATCH — When to Use Which


ScenarioUse
Replacing a whole document/profilePUT
Updating 1 or 2 fields on a large objectPATCH
Unknown which fields changedPATCH
Third-party API must receive complete replacementPUT



6. DELETE — Removing a Resource


DELETE removes the resource at the given URL.


// Delete a course by ID
const response = await fetch('/api/courses/42', {
  method: 'DELETE',
  headers: { 'Authorization': `Bearer ${token}` }
});

if (response.status === 204) { console.log('Deleted successfully'); } else if (response.status === 404) { console.log('Course not found — already deleted?'); }


  • Response is usually 204 No Content (success, no body)
  • Or 200 OK with a confirmation body
  • Idempotent — deleting something that's already gone returns the same state (though status might be 404)



7. HEAD — Check Before You Download


HEAD is identical to GET, but the server returns only the headers — no body. Use it to:


  • Check if a resource exists (without downloading it)
  • Get the file size (Content-Length) before downloading
  • Check if cached content is still fresh (ETag, Last-Modified)

// Check if a large file has changed before downloading it
const headRes = await fetch('/downloads/course-data.zip', {
  method: 'HEAD'
});

const size = headRes.headers.get('content-length'); const etag = headRes.headers.get('etag'); const changed = etag !== localStorage.getItem('last-etag');


console.log(File size: ${(size / 1024 / 1024).toFixed(1)} MB); console.log(Changed since last download: ${changed});


if (changed) { // Now download the full file const fullRes = await fetch('/downloads/course-data.zip'); const blob = await fullRes.blob(); localStorage.setItem('last-etag', etag); }




8. OPTIONS — CORS Preflight


OPTIONS is used automatically by browsers before certain cross-origin requests (CORS preflight). You rarely call it manually.


// Browser sends this automatically before a cross-origin PUT/DELETE/custom-header request
OPTIONS /api/users/99 HTTP/1.1
Host: api.otherdomain.com
Origin: https://nandhoo.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization, Content-Type

Server must respond with:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://nandhoo.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400



9. REST API Design with HTTP Methods


A well-designed REST API uses HTTP methods consistently:


Resource: /api/courses

GET /api/courses → List all courses POST /api/courses → Create a new course


GET /api/courses/:id → Get a specific course PUT /api/courses/:id → Replace a course entirely PATCH /api/courses/:id → Update part of a course DELETE /api/courses/:id → Delete a course HEAD /api/courses/:id → Check if a course exists


Nested resources: GET /api/courses/:id/chapters → List all chapters for a course POST /api/courses/:id/chapters → Add a chapter to a course DELETE /api/courses/:id/chapters/:cid → Remove a specific chapter


Method → Status Code Conventions


MethodSuccess Response
GET200 OK
POST201 Created + Location header
PUT / PATCH200 OK (with body) or 204 No Content
DELETE204 No Content
Any method (not found)404 Not Found
Any method (wrong method)405 Method Not Allowed



10. Common Mistakes


MistakeProblemFix
Using GET to delete data (e.g., /delete?id=42)Search engines can crawl and trigger deleteUse DELETE method
Using POST for read operationsNot cacheable, confusing for API consumersUse GET with query parameters
Using PUT when you mean PATCHClears fields the client didn't intend to removeUse PATCH for partial updates
Not returning 201 with a Location header on POSTClient has to make another request to find the new resourceReturn 201 + Location: /api/resource/new-id
Ignoring 405 Method Not AllowedAPI silently ignores unknown methodsCheck allowed methods in the Allow response header



11. Seeing All Methods In Practice


const API = 'https://api.nandhoo.com';
const headers = { 
  'Content-Type': 'application/json',
  'Authorization': `Bearer ${token}`
};

// 1. GET — fetch all courses const list = await fetch(${API}/courses, { headers }).then(r => r.json());


// 2. POST — create a course const created = await fetch(${API}/courses, { method: 'POST', headers, body: JSON.stringify({ title: 'HTTP Basics', level: 'beginner' }) }).then(r => r.json());


// 3. PUT — fully replace the course await fetch(${API}/courses/${created.id}, { method: 'PUT', headers, body: JSON.stringify({ title: 'HTTP Deep Dive', level: 'intermediate', chapters: 10 }) });


// 4. PATCH — only update the title await fetch(${API}/courses/${created.id}, { method: 'PATCH', headers, body: JSON.stringify({ title: 'HTTP Mastery' }) });


// 5. DELETE — remove the course await fetch(${API}/courses/${created.id}, { method: 'DELETE', headers });




12. Review Questions


  1. What is the difference between a safe and an idempotent method?
  2. Why should GET requests never have side effects?
  3. What is the key difference between PUT and PATCH?
  4. What status code should a successful POST return, and what extra header should it include?
  5. When would you use HEAD instead of GET?
  6. What happens if you send a DELETE request to a URL that no longer exists?
  7. Why is POST not idempotent?