What Is an API, Actually?
A plain explanation of APIs — what the word means, how a request travels from your app to a server and back, the main kinds you'll meet (REST, GraphQL, WebSockets, gRPC), and how to read one for the first time.

Start with something you already use
Open a weather app. It shows 31°C in Riyadh. The app did not measure that. It asked a server:
GET https://api.weather.example/v1/current?city=Riyadh
And the server answered:
{
"city": "Riyadh",
"temperature_c": 31,
"condition": "clear",
"updated_at": "2026-09-05T09:00:00Z"
}
That exchange — a structured question, a structured answer, over a network — is an API call. The app is the client. The weather service is the server. The agreed format of the question and the answer is the API.
That is the whole idea. Everything else is detail.
The word itself
API stands for Application Programming Interface. Break it down:
- Interface — a boundary you interact with without seeing what is behind it. A light switch is an interface to your house's wiring.
- Programming — this interface is meant to be used by code, not by a person clicking buttons.
- Application — the thing exposing it is a program or service.
So: a way for one program to use another program's functionality, without knowing how that functionality is built.
The weather app does not know whether the service reads satellites or scrapes a government site. It only knows: send this request, get back this shape.
APIs are not only about the web
The term is older and broader than HTTP. Any of these is an API:
# Python's standard library exposes an API for file paths
from pathlib import Path
Path("notes.txt").read_text()
// The browser exposes a DOM API to JavaScript
document.querySelector("h1").textContent = "Hello";
// The operating system exposes a system-call API to C
int fd = open("/etc/hosts", O_RDONLY);
In each case: functions you call, arguments you pass, results you get back, and no need to read the implementation. The interface is the contract.
When people say "API" today without qualification, they almost always mean a web API — a server you talk to over HTTP. That is what the rest of this article covers.
Anatomy of a request
Every HTTP API call has the same parts. Here is a real one, written out longhand:
POST /api/contact HTTP/1.1
Host: mostafa.dev
Content-Type: application/json
Authorization: Bearer 1|Xk9fQ2mL8pR4tV7wY0zB3cD6eF9gH2jK
{
"email": "reader@example.com",
"body": "Liked the Python errors article."
}
Line by line:
| Part | Value | Meaning |
|---|---|---|
| Method | POST | What kind of action. GET reads, POST creates, PUT/PATCH update, DELETE removes. |
| Path | /api/contact | Which resource you are talking about. |
| Host | mostafa.dev | Which server. |
| Headers | Content-Type, Authorization | Metadata: what format the body is in, who you are. |
| Body | the JSON | The actual data you are sending. GET requests usually have none. |
Think of it as a letter. Method is the verb on the envelope, path is the address, headers are the postmarks and stamps, body is the letter inside.
Anatomy of a response
The server writes back in the same format:
HTTP/1.1 201 Created
Content-Type: application/json
{
"data": {
"id": 118,
"email": "reader@example.com",
"received_at": "2026-09-05T09:04:12Z"
}
}
| Part | Value | Meaning |
|---|---|---|
| Status code | 201 | A three-digit number saying how it went. |
| Headers | Content-Type | Metadata about the response. |
| Body | the JSON | The result. |
The status code is the first thing a client checks. The ranges are worth memorising:
- 2xx — worked.
200 OK,201 Created,204 No Content. - 3xx — go somewhere else.
301moved permanently,304you already have the latest copy. - 4xx — your request was wrong.
400malformed,401not logged in,403logged in but not allowed,404doesn't exist,422invalid data,429slow down. - 5xx — the server broke.
500generic,502/503upstream or overloaded.
If you remember one rule: 4xx is your fault, 5xx is theirs.
Why JSON
Nearly every modern web API speaks JSON — JavaScript Object Notation:
{
"title": "Portfolio CMS",
"featured": true,
"stars": 42,
"tags": ["Laravel", "Vue"],
"author": { "name": "Mostafa", "github": "Mostafame8" },
"archived_at": null
}
Six types: string, number, boolean, array, object, null. That is enough to
describe almost anything, every language can parse it, and a human can read it
in a terminal. XML did the same job in the 2000s with roughly three times the
characters. JSON won.
Where the URL comes from
Look at a typical set of endpoints:
GET /api/projects all projects
GET /api/projects/12 project number 12
POST /api/projects create a project
PATCH /api/projects/12 edit project 12
DELETE /api/projects/12 delete project 12
The pattern: the URL names a thing (a noun), the method says what to do to it (a verb). Same URL, different method, different action. Nested things nest in the path:
GET /api/projects/12/tags tags belonging to project 12
And options that narrow a list go after a ? as query parameters:
GET /api/projects?featured=true&sort=-created_at&page=2
That style — nouns in the path, verbs as methods, JSON bodies — is called REST. Most APIs you meet follow it loosely.
Authentication: proving who you are
A public weather endpoint needs no identity. Anything that reads private data or changes something needs to know who is asking. Three common mechanisms:
API key. A long random string you get from a dashboard and send with every request. Simplest. Identifies the application, not a user.
GET /v1/forecast
X-Api-Key: wk_live_8f2a9c...
Bearer token. You log in once, receive a token, send it in the
Authorization header until it expires. Identifies a user session. This is
what most apps use; JWTs and Laravel Sanctum tokens are both variants.
GET /api/me
Authorization: Bearer eyJhbGciOi...
OAuth. The "Sign in with Google" flow. You never see the user's Google password; Google hands you a scoped token that says "this user allows you to read their calendar and nothing else." More steps, much safer for third-party access.
Whichever is used, the failure codes are the same: 401 if the credentials
are missing or bad, 403 if they are fine but not enough.
Calling one yourself
You do not need to build anything to try an API. From a terminal:
curl https://api.github.com/users/Mostafame8
{
"login": "Mostafame8",
"public_repos": 27,
"followers": 12,
"created_at": "2019-03-11T14:22:08Z"
}
From JavaScript in a browser or Node:
const res = await fetch("https://api.github.com/users/Mostafame8");
const user = await res.json();
console.log(user.public_repos); // 27
From Python:
import requests
user = requests.get("https://api.github.com/users/Mostafame8").json()
print(user["public_repos"]) # 27
From a Nuxt page, the same thing with caching and SSR handled for you:
const { data: user } = await useFetch(
"https://api.github.com/users/Mostafame8"
);
Four languages, one API, identical result. That portability is the point.
The other kinds you will meet
REST over HTTP is the default, but it is not the only shape.
GraphQL. One endpoint, and the client sends a query describing exactly which fields it wants:
{
project(slug: "portfolio-cms") {
title
tags { name }
}
}
Good when clients vary a lot (a mobile app wants three fields, a dashboard wants thirty). Costs: a query language to learn, harder caching, easy to write expensive queries by accident.
WebSockets. REST is request → response → done. A WebSocket stays open in both directions, so the server can push to the client without being asked. Chat, live dashboards, multiplayer cursors.
const ws = new WebSocket("wss://live.example/prices");
ws.onmessage = (e) => console.log(JSON.parse(e.data));
gRPC. Binary instead of JSON, with a strict schema file (.proto) that
generates client code in any language. Fast and type-safe. Common between
backend services; awkward directly from a browser.
Webhooks. An API in reverse. Instead of you polling "any new payments?",
Stripe sends an HTTP POST to your URL the moment one happens. You write the
server side; they are the client.
SOAP. XML-based, verbose, strict. You will find it in banking, government, and any system built before 2010. You will not choose it for anything new.
Reading API documentation
Every API you use comes with docs. They all contain the same things, under different headings. Look for:
- Base URL —
https://api.example.com/v1. Everything is relative to this. - Authentication — which of the three mechanisms above, and where to get credentials.
- Endpoints — a list of method + path pairs with what they do.
- Request parameters — for each endpoint, what goes in the path, query, headers, body. Which are required.
- Response shape — an example JSON body. Copy this into your code as a type or a test fixture.
- Error codes — which
4xxs this API uses and what the body looks like. - Rate limits — how many requests per minute before
429.
The single fastest way to learn an API: find one example request in the docs,
paste it into curl, and look at what comes back. Then change one thing.
Common first mistakes
- Putting the API key in frontend code. Anything shipped to a browser is public. Keys belong on a server that the browser talks to instead.
- Ignoring the status code.
fetchdoes not throw on404or500. Checkres.okbefore calling.json(). - Calling in a loop. Fifty items, fifty requests. Look for a list endpoint or a batch parameter first.
- Not handling
null. Optional fields come back asnull, not missing.user.company.namecrashes whencompanyisnull. - Trusting the shape forever. Pin the fields you use in a type. When the API adds or renames a field you find out at compile time, not from a user.
In one paragraph
An API is an agreement: send a request shaped like this, get a response shaped like that. Over the web, the request is an HTTP method plus a URL plus optional headers and a JSON body; the response is a status code plus headers plus a JSON body. REST arranges those around nouns and verbs. GraphQL, WebSockets, gRPC, and webhooks are variations for different needs. Authentication says who is asking. Documentation tells you the shapes. Once you can read one API, you can read all of them — the parts never change, only the names.