Skip to main content
ANVISoftware Solutions
Lesson 1 of 23Intermediate16 min

HTTP Fundamentals

By the end of this lesson

Describe requests, responses, methods, headers and status codes accurately.

Every conversation with a web API has the same shape. A client sends one request. The server sends back one response. Then neither side remembers anything about it.

HTTP is the format of those two messages. It is text, it is readable, and it is worth reading directly at least once. Frameworks hide it well enough that you can build a working API without ever seeing a raw request, and then you cannot explain why a caller is failing.

That last sentence about memory is the property called statelessness. Nothing carries over between requests. If the server needs to know who is calling, that fact travels inside the request itself, which is why a token is sent on every call rather than once at the start.

One request and its response, as they travel
HTTP
GET /api/employees/482?include=department HTTP/1.1
Host: directory.example.com
Accept: application/json
Authorization: Bearer REPLACE-WITH-YOUR-TOKEN

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{
  "id": 482,
  "fullName": "Priya Raman",
  "department": { "code": "FIN", "name": "Finance" }
}
  • The first line of the request is the request line: the method, the target and the protocol version. Those three pieces decide almost everything that follows.
  • The target carries two separate ideas. /api/employees/482 is the path, and it identifies a resource. include=department is the query string, and it modifies how that resource is returned.
  • Each line after the request line is a header: a name, a colon, a value. Headers describe the message. Accept states what the client can read, and Authorization carries the credential. Neither belongs in the path, because neither identifies the thing being addressed.
  • A blank line separates headers from the body. This GET request has no body, so nothing follows it.
  • The response opens with the status line, and 200 OK is the part every caller reads first. Its own headers describe the body that follows, then a blank line, then the body itself.
  • Content-Type is how the client knows to parse the body as JSON. Sending JSON without it is a common cause of a caller that works in one language and fails in another.

The method is a statement of intent, and two properties of that intent have names you will meet constantly. A method is safe when it is not supposed to change anything. It is idempotent when sending the same request several times leaves the server in the same state as sending it once. Both matter in practice: browsers, proxies and retry logic all act on these assumptions.

 Safe — changes nothing?Idempotent — repeat is harmless?
GET — read a resourceYes. A GET that modifies data breaks caches and retries.Yes. Ten identical reads leave the same state.
POST — create, or ask for an actionNo. It exists to change something.No. Two identical POSTs usually create two employees.
PUT — replace a resource at a known addressNoYes. The same body sent twice leaves one employee with that content.
PATCH — change part of a resourceNoIt depends on the patch. Set the salary to 50000 is idempotent; add 1000 to the salary is not.
DELETE — remove a resourceNoYes in effect. The first call removes it, and later calls find nothing to remove.

Status codes are the part callers depend on most

Responses fall into five families, and the first digit carries the message: 1xx informational, 2xx succeeded, 3xx look elsewhere, 4xx the caller made a mistake, 5xx the server made one. That split is what lets a client decide what to do without understanding your application. Ten specific codes cover nearly everything an API needs.

200 OK
It worked and there is a body to read. The default for a read, and for an update that returns the updated resource.
201 Created
Something new exists. Send a Location header holding its address so the caller does not have to construct the URL of the thing it just created.
204 No Content
It worked and there is deliberately nothing to send. A delete, or an update where returning the resource adds nothing.
400 Bad Request
The request is malformed or fails a basic rule. The caller has to change something before retrying.
401 Unauthorized
No usable credential was presented, or it has expired. The name is misleading: this one means unauthenticated.
403 Forbidden
The caller is known and is not allowed to do this. Repeating the call with the same credential cannot help.
404 Not Found
There is nothing at this address. Also used deliberately when confirming that a record exists would itself leak information.
409 Conflict
The request is valid and clashes with the current state. Two people editing the same employee, or an email address already in use.
422 Unprocessable Content
The syntax is fine and the meaning fails validation. Plenty of teams use 400 for this too. Either is defensible; inconsistency inside one API is not.
500 Internal Server Error
Your code failed. The caller did nothing wrong and cannot fix it, so the body should say almost nothing about your internals.

Summary

  • A request is a method, a target, headers and an optional body; a response is a status code, headers and an optional body
  • HTTP is stateless, so anything the server needs to know travels in each request
  • Method intent matters: GET is safe, PUT and DELETE are idempotent, POST is neither
  • The first digit of a status code tells a caller whether to fix the request, retry, or escalate
  • Returning 200 for a failure breaks every caller, proxy and dashboard that reads status codes

Practice

Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.

Try it yourself

Choose the status code

For each outcome of the employees API, pick the status code you would return and write one line on why.

1. A GET for employee 482, who exists. 2. A GET for employee 999999, who does not. 3. A POST that creates a new employee. 4. A POST missing the required surname field. 5. A PUT whose email address already belongs to a different employee. 6. A DELETE that succeeds and has nothing to return.

Show solution

200, 404, 201, 400, 409, 204.

The 201 is the one people most often get wrong by returning 200. The difference is useful: 201 also carries a Location header, so the caller learns the address of the new employee instead of guessing it or making a second call to find it.

The 409 rather than 400 is a judgement call worth making deliberately. The request was well formed and would have worked yesterday, so the problem is the current state of the data rather than the shape of the request. A caller can act differently on those two cases, which is the whole reason for distinguishing them.

The 204 for a delete says the outcome is complete and there is nothing to read. Returning 200 with an empty object instead invites callers to parse a body that will never contain anything.

Think about it

The cost of one wrong status code

A team ships an API where every response is 200, and failures are reported in the body with an ok field.

Name three things this breaks outside the code that calls the API. Then decide how much work it would be to change once fifty clients depend on it.

Show solution

Monitoring and alerting break first, because error rates are almost always measured from status codes. The dashboards will show a perfectly healthy service during an outage.

Caches and proxies break next. They decide what is cacheable and what is worth retrying from the status code, so a failure that says 200 can be stored and served again to somebody else.

Generic client libraries break. Anything that raises an error on a non-2xx response, which is most of them, will treat every failure as success and carry on with a body it cannot use.

Changing it later is a breaking change for every caller, because clients that currently check the ok field will start receiving exceptions from their own HTTP library. That is the real cost: the decision looks local when you make it and is not.

Knowledge check

Nothing is recorded and there is no score. The explanation appears either way.

A DELETE for employee 482 succeeds. The same DELETE is sent again and returns 404. Is the endpoint idempotent?
A PUT updating an employee fails because the email address in the body already belongs to a different employee. Which status code fits best?

Saved in this browser only.