RizTech Academy logo
RizTech Academy
How a Full-Stack Application Fits TogetherLesson 3 of 430 min

HTTP, REST and the life of a request

Every conversation between the two halves is an HTTP request and a response. You have used HTTP for years without reading one. This lesson makes it concrete, because API design is mostly HTTP design.

A request

GET /api/products?category=grains&page=2 HTTP/1.1
Host: api.kirana.example
Accept: application/json
Authorization: Bearer eyJhbGci...

Four parts:

Method — GET. What kind of operation. Path — /api/products. Which resource. Query string — ?category=grains&page=2. Parameters. Headers — metadata: what format is wanted, who is asking.

A POST, PUT or PATCH also carries a body:

POST /api/orders HTTP/1.1
Content-Type: application/json

{"items": [{"productId": "atta-5kg", "quantity": 2}]}

That is the whole shape. Everything else is detail.

A response

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

{"data": [...], "page": 2, "total": 47}

A status code, headers, and usually a body.

The methods

Method Means Safe Idempotent
GET read something yes yes
POST create, or "do something" no no
PUT replace entirely no yes
PATCH update partially no no
DELETE remove no yes

Two words worth defining, because they drive real decisions:

Safe means it changes nothing. A GET must never alter data — browsers, proxies and crawlers all assume this, and a GET /products/5/delete will eventually be triggered by something that was only trying to look.

Idempotent means doing it twice has the same effect as once. DELETE on an already-deleted item changes nothing further.

POST is not idempotent, which is exactly why double-clicking a submit button creates two orders. Module 12 handles that properly; for now, notice the property is what causes the bug.

Status codes

The first digit tells you the category:

  • 2xx — it worked
  • 3xx — look elsewhere
  • 4xx — the client got it wrong
  • 5xx — the server got it wrong

The ones you will actually use:

Code When
200 OK a successful read or update
201 Created a successful create
204 No Content success, nothing to return — often DELETE
400 Bad Request malformed or invalid input
401 Unauthorized not logged in
403 Forbidden logged in, not allowed
404 Not Found no such resource
409 Conflict clashes with current state — out of stock
422 Unprocessable well-formed but semantically wrong
429 Too Many Requests rate limited
500 Internal Server Error you have a bug

401 versus 403 catches everyone. 401 means "I do not know who you are" — logging in might fix it. 403 means "I know exactly who you are and no" — logging in again will not help.

4xx is your fault, 5xx is mine. If a user sends bad data and you return 500, you are telling them your server broke when it did not — and you will get support tickets for it. Getting this split right is most of what makes an API pleasant to consume.

REST, briefly

REST is a set of conventions for mapping URLs and methods onto resources. It is not a specification you can fail, and most "REST APIs" are approximate. What matters is being predictable.

The convention:

GET    /products           list
POST   /products           create
GET    /products/42        read one
PATCH  /products/42        update
DELETE /products/42        delete

GET    /products/42/reviews    nested resource

The principles worth keeping:

Nouns in paths, verbs as methods. /products, not /getProducts. The method already says what you are doing, so POST /createProduct says it twice.

Plural, consistently. /products/42, never /product/42. Pick one and never mix.

Nest only one level. /products/42/reviews is fine. /categories/3/products/42/reviews/7 is not — use /reviews/7.

Filtering and sorting in the query string, not the path:

GET /products?category=grains&sort=price&order=asc&page=2&limit=20

When REST does not fit

Some operations are not CRUD. Cancelling an order is not "update order".

POST /orders/42/cancel
POST /cart/checkout
POST /auth/login

These are verbs, and that is fine. Forcing PATCH /orders/42 with {"status": "cancelled"} looks more RESTful and is worse — it implies any status transition is allowed, when cancelling has its own rules.

Be consistent rather than pure. An API somebody can predict beats one that satisfies a specification.

Headers that matter

Content-Type: application/json — what you are sending. Accept: application/json — what you want back. Authorization: Bearer <token> — who you are. Module 8. Cache-Control — how long this may be reused. Significant for a shop, where product pages change rarely and carts change constantly. Set-Cookie — the server storing something in the browser. Module 8 again.

Seeing it yourself

curl -i https://api.github.com/repos/facebook/react

-i includes the response headers. Read the status line, the content type, the caching headers.

curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"hello": "world"}'

httpbin.org echoes back what it received, which makes it a good place to see exactly what your request looked like.

Your browser's Network tab shows the same for every request a page makes. Spend ten minutes in there on a site you use — it is the fastest way to make this concrete.

What this means for design

Every endpoint you write in module 7 is a decision about method, path, status code and body shape. Get those right and a front-end developer can guess your API. Get them wrong and they need documentation for every call.

The test: could somebody predict the URL and method for an operation they have not seen? If yes, the design is working.

Check your work

Methods and paths: list all products GET /products · get product 42 GET /products/42 · add a review POST /products/42/reviews · delete review 7 DELETE /reviews/7 · search GET /products?q=atta · page 3 of grains GET /products?category=grains&page=3 · cancel order 12 POST /orders/12/cancel.

Status codes: successful login 200 · wrong password 401 · valid token but not an admin 403 · product does not exist 404 · out of stock at checkout 409 · database down 500.

Why GET /products/5/delete is a bad idea: GET must be safe. Crawlers, prefetchers and proxies follow GET links freely, so something will eventually delete your products just by looking.

Why a double-clicked button creates two orders: POST is not idempotent, so performing it twice has twice the effect.

What a cart request looks like: a PATCH or POST to a cart endpoint, sending an item id and a quantity — not a price — and returning 200.

Practice

  1. curl -i a public API. Identify the status line, three headers and the body.
  2. Use httpbin to send a POST with a JSON body. Read back what arrived.
  3. Write the method and path for: list all products · get product 42 · add a review to product 42 · delete review 7 · search for "atta" · get page 3 of grains · cancel order 12.
  4. For each, pick a status code: successful login · wrong password · valid token but not an admin · product does not exist · out of stock at checkout · your database is down.
  5. Explain in one sentence why GET /products/5/delete is a bad idea even though it works.
  6. Explain why a double-clicked submit button creates two orders, using the word idempotent.
  7. Open a shop's Network tab, add something to the cart, and write down the method, path, request body and status code.

Next: setting up the project you will build for the rest of the course.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship