When I started backend development, I kept seeing terms like:

  • HTTP methods
  • GET, POST, PUT, PATCH, DELETE
  • status codes
  • headers
  • REST
  • statelessness
  • idempotency
  • resources

At first, they felt like a bunch of rules I just had to memorize.

But once I understood what actually happens when a browser or frontend talks to a backend, these concepts started fitting together.

This blog is my attempt to understand HTTP and REST as a conversation between a client and a server.

1. The Basic Idea: Client Talks to Server

Whenever we use an application, there is usually some communication happening between a client and a server.

For example, imagine a Twitter-like application.

I open my profile.

The frontend might send:

GET /users/123 

The server processes the request and sends something back:

HTTP/1.1 200 OK Content-Type: application/json 
{ "id": 123, "name": "Koushik" } 

That's HTTP communication.

The basic pattern is:

Client | | HTTP Request v Server | | HTTP Response v Client 

This is the foundation of most web APIs.

2. What Is HTTP?

HTTP stands for:

HyperText Transfer Protocol

It is a protocol that defines how clients and servers communicate.

A client could be:

  • browser
  • React application
  • mobile app
  • Postman
  • another backend service

A server could be:

  • Node.js server
  • Express application
  • NestJS application
  • Java/Spring application
  • Python/Django application
  • Go server

The important thing is that both sides understand the HTTP rules.

3. The Request/Response Cycle

This is one of the most important concepts to understand.

Let's say I open:

GET /users/123 

The process roughly looks like this:

1. Client creates request ↓ 2. Request travels to server ↓ 3. Server receives request ↓ 4. Server finds the route ↓ 5. Server runs application logic ↓ 6. Server may query a database ↓ 7. Server creates response ↓ 8. Response travels back ↓ 9. Client receives response 

Let's go through it.

4. Step 1: The Client Creates a Request

Suppose my frontend wants to get a user.

It might send:

GET /users/123 HTTP/1.1 Host: api.example.com Accept: application/json Authorization: Bearer token 

This request contains information telling the server what the client wants.

5. Step 2: The Request Travels to the Server

The request travels over the network.

The client needs to know where the server is.

For example:

https://api.example.com/users/123 

The browser or HTTP client handles things like:

  • DNS lookup
  • establishing a network connection
  • TLS encryption for HTTPS
  • sending the HTTP request

We don't usually think about all of these steps when writing backend code, but they happen underneath.

6. Step 3: The Server Receives the Request

Our Node.js application receives the HTTP request.

For example:

const http = require("node:http"); const server = http.createServer((req, res) => { console.log(req.method); console.log(req.url); }); server.listen(3000); 

If the client sends:

GET /users/123 

we can access:

req.method 

which gives:

GET 

and:

req.url 

which gives:

/users/123 

7. Step 4: Routing

The server needs to figure out:

"What code should handle this request?"

For example:

GET /users GET /users/123 POST /users PATCH /users/123 DELETE /users/123 

Each route can perform a different operation.

In a framework like Express or NestJS, routing becomes much easier to organize.

8. Step 5: Business Logic

Once the correct route is found, the application performs its work.

For example:

GET /users/123 ↓ Find user 123 ↓ Check permissions ↓ Fetch user from database ↓ Create response 

The server might interact with:

  • PostgreSQL
  • MongoDB
  • Redis
  • another API
  • file storage

9. Step 6: The Server Sends a Response

The server eventually sends something back.

For example:

HTTP/1.1 200 OK Content-Type: application/json 
{ "id": 123, "name": "Koushik" } 

The response tells the client:

"Here is the result of your request."

10. The Complete Story

So the entire process looks like:

Frontend | | GET /users/123 ↓ HTTP Server | ↓ Router | ↓ Controller | ↓ Service | ↓ Database | ↓ Service | ↓ Controller | ↓ HTTP Response | ↓ Frontend 

This pattern becomes very familiar when working with Node.js and NestJS.

11. HTTP Methods

HTTP methods describe what the client wants to do.

The most common methods are:

GET POST PUT PATCH DELETE 

Instead of inventing URLs like:

/createUser /getUser /updateUser /deleteUser 

REST APIs generally use the resource name and let the HTTP method describe the action.

For example:

GET /users POST /users GET /users/123 PATCH /users/123 DELETE /users/123 

The URL identifies the resource.

The method tells us what we want to do with it.

12. GET

GET means:

"Give me this resource."

Example:

GET /users/123 

The server might respond:

{ "id": 123, "name": "Koushik" } 

Another example:

GET /users 

could return a list of users.

GET should generally be safe

A GET request should not change the server's state.

For example:

GET /users/123 

shouldn't delete the user or change their name.

13. POST

POST is commonly used to create a new resource.

For example:

POST /users Content-Type: application/json 
{ "name": "Koushik", "email": "koushik@example.com" } 

The server may create:

User ID = 124 

and respond:

201 Created 

with the new resource.

14. PUT

PUT is commonly used to replace a resource with a new representation.

For example:

PUT /users/123 
{ "name": "Koushik", "email": "new@example.com" } 

Conceptually:

Old User ↓ Replace with ↓ New User representation 

PUT can also be used for an upsert-style operation depending on the API design, but the exact behavior should be documented.

The important idea is:

PUT represents replacing the target resource with the supplied representation.

15. PATCH

PATCH is generally used for a partial update.

Suppose the user currently has:

{ "id": 123, "name": "Koushik", "email": "old@example.com", "age": 20 } 

We only want to change the name.

We can send:

PATCH /users/123 
{ "name": "Koushik Maya" } 

Only the specified field needs to change.

So:

PUT → replace/update the complete representation PATCH → partially modify the resource 

In real APIs, the exact semantics of PATCH depend on the patch format and API design.

16. DELETE

DELETE means:

"Remove this resource."

Example:

DELETE /users/123 

The server may respond:

204 No Content 

There is no need to return the deleted user.

17. Quick HTTP Method Table

Method Typical Purpose Example
GET Read GET /users/123
POST Create/process POST /users
PUT Replace PUT /users/123
PATCH Partial update PATCH /users/123
DELETE Delete DELETE /users/123

18. What Is Idempotency?

This word sounds complicated, but the idea is simple.

A request is idempotent if making the same request multiple times has the same intended effect on the server's state as making it once.

For example:

PUT /users/123 

with:

{ "name": "Koushik" } 

If I send it once:

User name = Koushik 

If I send it five times:

User name = Koushik 

The final intended state is still the same.

That's idempotency.

19. GET Is Idempotent

Suppose:

GET /users/123 

I send it:

1 time → get user 10 times → get user 100 times → get user 

The server's resource state should not change.

GET is therefore considered idempotent and safe.

20. PUT Is Idempotent

Suppose:

PUT /users/123 
{ "name": "Koushik" } 

Sending it repeatedly should leave the resource in the same intended state.

Therefore, PUT is idempotent.

21. DELETE Is Idempotent

Suppose:

DELETE /users/123 

First request:

User exists ↓ Delete user 

Second request:

User already deleted 

The response may be different, such as 404 Not Found, but the intended final state is still:

User does not exist 

Therefore DELETE is considered idempotent.

This is an important distinction:

Idempotent does not mean every response must be identical.

It means repeated requests have the same intended effect on the resource state.

22. POST Is Generally Not Idempotent

Suppose:

POST /orders 
{ "productId": 10, "quantity": 1 } 

If I send it once:

Order #1001 created 

If I send it again:

Order #1002 created 

Now I have two orders.

So POST is generally not idempotent.

This is one reason duplicate POST requests can be dangerous for operations like:

  • payments
  • order creation
  • account creation

Some APIs solve this with an idempotency key.

23. What About PATCH?

PATCH is more nuanced.

PATCH is not automatically idempotent.

It depends on what the patch operation actually does.

For example, imagine:

PATCH /users/123 
{ "name": "Koushik" } 

Repeatedly applying that update may result in the same state.

But imagine a patch operation meaning:

increase balance by ₹100 

Repeating it could produce:

₹100 ₹200 ₹300 

So PATCH can be idempotent or non-idempotent depending on its semantics.

24. HTTP Status Codes

When a server responds, it sends a status code.

For example:

200 OK 

The first digit tells us the broad category.

1xx → Informational 2xx → Success 3xx → Redirection 4xx → Client Error 5xx → Server Error 

The categories are more important to memorize than every individual status code.

25. 1xx — Informational

These indicate that the request has been received and the process is continuing.

You won't use these directly very often in typical REST API development.

26. 2xx — Success

This means:

"The request was successfully handled."

Common examples:

200 OK

General successful response.

GET /users/123 → 200 OK 

201 Created

A resource was successfully created.

POST /users → 201 Created 

204 No Content

Successful request with no response body.

DELETE /users/123 → 204 No Content 

27. 3xx — Redirection

These indicate that the client may need to take another action or use another location.

A familiar example is:

301 Moved Permanently 

This tells clients that a resource has permanently moved.

Another is:

304 Not Modified 

which is commonly involved with caching.

28. 4xx — Client Errors

These generally mean:

"There is something wrong with the request from the client."

Common examples:

400 Bad Request

The request is invalid.

POST /users 

with malformed or invalid input might result in:

400 Bad Request 

401 Unauthorized

Authentication is required or the provided authentication is invalid.

A useful way to remember it:

"I don't know who you are."

403 Forbidden

The server understood who you are, but you don't have permission.

Think:

"I know who you are, but you're not allowed to do this."

404 Not Found

The requested resource doesn't exist.

GET /users/999999 → 404 Not Found 

409 Conflict

The request conflicts with the current state.

For example, trying to create a username that must be unique.

422 Unprocessable Content

The server understands the request format, but the submitted data fails validation or semantic rules.

29. 5xx — Server Errors

These generally mean:

"The server failed while trying to handle a valid request."

For example:

500 Internal Server Error 

Maybe our application crashed while processing the request.

Other examples include:

502 Bad Gateway 503 Service Unavailable 504 Gateway Timeout 

These are especially important when dealing with distributed systems and reverse proxies.

30. Status Code Mental Model

I find this easier to remember:

2xx "Everything worked." 3xx "Go somewhere else / use cached information." 4xx "Your request has a problem." 5xx "Something went wrong on the server." 

31. HTTP Headers

Headers are metadata attached to HTTP requests and responses.

Think of them like labels attached to a package.

The package contains the actual content.

The labels tell us things about it.

For example:

Content-Type: application/json Authorization: Bearer abc123 Cache-Control: no-cache 

32. Content-Type

Content-Type tells the receiver what format the message body uses.

For example:

Content-Type: application/json 

means:

"The body contains JSON."

A request might look like:

POST /users Content-Type: application/json 
{ "name": "Koushik" } 

Other examples include:

text/plain text/html multipart/form-data application/xml 

This becomes particularly important when uploading files.

33. Accept Header

Although not in the original list, Accept is worth knowing alongside Content-Type.

Content-Type describes:

"What I am sending."

Accept describes:

"What I would like to receive."

For example:

Content-Type: application/json Accept: application/json 

This distinction is very useful when working with APIs.

34. Authorization

The Authorization header is commonly used to send authentication credentials.

For example:

Authorization: Bearer eyJhbGciOi... 

The server can use the token to determine:

  • who the user is
  • whether the token is valid
  • what the user is allowed to do

A common pattern is:

Client | | Authorization: Bearer token ↓ Server | ↓ Validate token | ↓ Identify user 

Important:

Authentication answers "Who are you?"

Authorization answers "Are you allowed to do this?"

35. Cache-Control

Cache-Control tells clients and intermediate caches how a response may be cached.

For example:

Cache-Control: max-age=3600 

This can indicate that the response can be considered fresh for a certain period.

Another example:

Cache-Control: no-store 

means the response should not be stored by a cache.

Caching can dramatically reduce unnecessary requests and improve performance.

36. Headers + Body

An HTTP message can be thought of like this:

HTTP Request ├── Method ├── URL ├── Headers └── Body 

Example:

POST /users HTTP/1.1 Content-Type: application/json Authorization: Bearer token 
{ "name": "Koushik" } 

And the response:

HTTP Response ├── Status Code ├── Headers └── Body 

Example:

HTTP/1.1 201 Created Content-Type: application/json 
{ "id": 123, "name": "Koushik" } 

37. What Does Stateless Mean?

REST APIs are commonly described as stateless.

At first this sounds like:

"The server doesn't remember anything."

That's not quite right.

Stateless means:

Each request should contain the information necessary for the server to understand and process that request.

The server shouldn't have to rely on hidden conversational state from a previous request.

38. Example of Stateless Authentication

Suppose I make:

GET /profile Authorization: Bearer abc123 

The server validates the token and identifies me.

Then I make another request:

GET /orders Authorization: Bearer abc123 

The second request contains the authentication information it needs.

The server doesn't need to think:

"This must be the same person who called /profile five seconds ago."

Each request carries the required context.

39. Why Statelessness Is Useful

Imagine you have three backend servers:

 Load Balancer / | \ / | \ Server A Server B Server C 

A user makes one request:

Request 1 → Server A 

Another request might go:

Request 2 → Server C 

If the request contains the necessary authentication/context, any server can process it.

This makes horizontal scaling easier.

40. Stateless Does NOT Mean No Database

This is an important distinction.

A stateless API can absolutely use a database.

For example:

Request ↓ API Server ↓ Database ↓ Response 

The database stores persistent application data.

Statelessness is about request-to-request application state, not about whether the application has storage.

41. REST

REST stands for:

Representational State Transfer

The name sounds intimidating, but the practical idea is much easier.

REST encourages us to model our API around resources.

Examples of resources:

users posts comments orders products 

Instead of thinking:

"What function should this URL call?"

think:

"What resource am I working with?"

42. Resource Naming

A good REST API usually uses nouns rather than verbs.

Prefer:

GET /users 

instead of:

GET /getUsers 

Prefer:

POST /users 

instead of:

POST /createUser 

The HTTP method already tells us the action.

43. Resource Naming Examples

Good:

/users /users/123 /posts /posts/123 /comments /comments/456 

Less REST-like:

/getUsers /createUser /updateUser /deleteUser /getAllPosts 

The idea is:

HTTP Method + Resource URL 

together describe the operation.

44. Collections vs Individual Resources

A collection represents multiple resources:

/users 

A specific resource:

/users/123 

So:

GET /users 

means:

"Give me users."

While:

GET /users/123 

means:

"Give me user 123."

This distinction becomes extremely useful when designing APIs.

45. Nested Resources

Sometimes a resource belongs naturally to another resource.

For example:

/users/123/posts 

could mean:

Posts belonging to user 123.

Or:

/posts/456/comments 

could mean:

Comments belonging to post 456.

But nesting should not become unnecessarily deep.

Avoid things like:

/users/123/posts/456/comments/789/likes/10 

if a simpler resource structure communicates the relationship.

46. Plural Resource Names

A common convention is to use plural nouns:

/users /posts /orders /products 

This makes collection endpoints intuitive.

For example:

GET /products POST /products GET /products/10 PATCH /products/10 DELETE /products/10 

47. URLs Should Identify Resources

One of the biggest ideas in REST is:

The URL should identify the resource, while the HTTP method describes the operation.

For example:

GET /users/123 POST /users PATCH /users/123 DELETE /users/123 

We don't need five completely different URLs.

The resource is:

/users/123 

The method changes what we want to do with it.

48. Query Parameters

Query parameters are useful for filtering, sorting, searching, and pagination.

For example:

GET /users?role=admin 

or:

GET /posts?limit=20&cursor=abc123 

The path identifies the resource:

/posts 

The query parameters describe how we want the collection represented.

49. A Real Example: Social Media API

Let's imagine we're building a Twitter-like application.

Get posts

GET /posts 

Get one post

GET /posts/123 

Create a post

POST /posts 
{ "content": "Learning Node.js!" } 

Update a post

PATCH /posts/123 
{ "content": "Learning Node.js and NestJS!" } 

Delete a post

DELETE /posts/123 

This is much easier to understand than creating action-based URLs for everything.

50. Putting the Whole Concept Together

Imagine I click:

"Create Post"

The frontend sends:

POST /posts Content-Type: application/json Authorization: Bearer token 
{ "content": "Learning Node.js!" } 

The server receives the request.

Request ↓ Routing ↓ Authentication ↓ Validation ↓ Business Logic ↓ Database ↓ Response 

The server might respond:

HTTP/1.1 201 Created Content-Type: application/json Cache-Control: no-cache 
{ "id": 501, "content": "Learning Node.js!", "authorId": 123 } 

Now almost every concept from this blog has appeared:

  • HTTP
  • request/response cycle
  • POST
  • headers
  • Content-Type
  • Authorization
  • status code
  • REST resource
  • database
  • response body

51. A Simple Mental Model

If I had to remember everything with one diagram:

 HTTP | ┌─────────┴─────────┐ | | REQUEST RESPONSE | | ┌────┴────┐ ┌────┴────┐ | | | | Method Headers Status Headers | | | | URL Body Body Body | ├── GET ├── POST ├── PUT ├── PATCH └── DELETE 

And REST gives us a way to organize the URLs around resources:

/users /users/123 /posts /posts/123 /orders /orders/123 

52. Quick Revision Cheat Sheet

Topic Simple Meaning
HTTP Rules for client-server communication
Request Message sent by client
Response Message sent by server
GET Read a resource
POST Create/process something
PUT Replace a resource representation
PATCH Partially modify a resource
DELETE Remove a resource
Idempotent Repeating the request has the same intended state effect
2xx Success
3xx Redirection
4xx Client-side/request problem
5xx Server-side problem
Content-Type Format of the message body
Authorization Credentials used to authenticate/authorize a request
Cache-Control Caching instructions
Stateless Each request carries the context needed to process it
REST Resource-oriented API design style
Resource Something represented by the API
Query parameter Filtering/sorting/pagination/search information

53. Final Takeaway

The biggest thing I learned is that HTTP isn't just:

"GET gets data and POST sends data."

There is a much bigger picture.

A client sends a request.

The request has:

Method URL Headers Body 

The server processes it and sends a response containing:

Status Code Headers Body 

HTTP methods communicate intent:

GET → read POST → create/process PUT → replace PATCH → partially modify DELETE → remove 

Status codes communicate the result:

2xx → success 3xx → redirection 4xx → client/request problem 5xx → server problem 

Headers provide metadata:

Content-Type Authorization Cache-Control 

And REST gives us a clean way to organize the API around resources:

/users /posts /orders /products 

Once this mental model is clear, frameworks like Express.js and NestJS become much easier to understand.

They aren't replacing HTTP.

They're giving us better tools for building applications that communicate using HTTP.

And that's the real foundation of backend development.