What Is an API
An API (Application Programming Interface) is a contract that lets one program talk to another. A web API speaks HTTP: a client sends a request, the server sends back a response — usually carrying JSON data.
REST (Representational State Transfer) is the most common style for designing such APIs. It is not a protocol or a library — it is a set of rules for how to shape the URLs, methods and responses. HTTP transfers the data; REST says how to organize it.
The central idea is the resource: every thing your API manages — a user, an order, a photo — has its own URL, like /users/7.
The Rules of REST
REST rests on a few principles:
Client–server — the two sides are separate and evolve separately.
Stateless — every request carries everything the server needs; the server remembers nothing between requests.
Uniform interface — the same URLs, methods and status codes mean the same things everywhere.
Cacheable — responses can say "you may reuse this answer", saving round trips.
Layered — proxies, gateways and load balancers can sit between client and server without either noticing.
One Request, One Response
Every API interaction is this cycle: a request (method + URL + optional body) goes out, a response (status code + headers + body) comes back. Here is one full round trip in Python — the demo starts a tiny local server in a background thread, so the program can run and finish on its own.
A full round trip
The client asks GET /users/1; the server answers with status 200 OK, a content type, and a JSON body. Every page in this group builds on this cycle.
One demo detail: the handler overrides log_message with an empty method. The base class would print a timestamped log line for every request, and the demo wants exactly the output shown — nothing else.
Output: complete Python program
import threading
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{"id": 1, "name": "Ana"}')
def log_message(self, fmt, *args):
pass # silence the built-in request log so the output stays clean
# A tiny server for the demo (a real one would block on serve_forever).
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
port = server.server_address[1]
threading.Thread(target=server.serve_forever, daemon=True).start()
with urllib.request.urlopen(f"http://127.0.0.1:{port}/users/1") as resp:
print("request: GET /users/1")
print("status: ", resp.status, resp.reason)
print("type: ", resp.headers["Content-Type"])
print("body: ", resp.read().decode())
server.shutdown()
Methods, Status Codes and Limits
The HTTP methods map onto the four data operations (CRUD):
GET read a resource · POST create one · PUT replace one · PATCH change part of one · DELETE remove one.
Status codes tell how it went: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error.
And REST has honest limits: it is not built for real-time streams, a response may carry more or less than the client wanted, and versioning a public API takes discipline. Knowing the limits is part of knowing the style.