API stands for Application Programming Interface. In plain terms: an API is a contract that lets two pieces of software talk to each other. One side asks for something; the other side responds — without either side knowing (or caring) how the other is built internally.
If you've ever logged in with Google, checked the weather on a phone app, or embedded a map in a website, you've used an API.
API in 30 seconds
| Term | What it means |
|---|---|
| API | Application Programming Interface — a contract for software to communicate |
| Request | A message from the caller asking for data or an action |
| Response | The answer — usually data (JSON, XML) or a status confirmation |
| Endpoint | A specific URL or address the API exposes (e.g. /users/42) |
| Client | The app or code making the request |
| Server | The app or service receiving and responding to requests |
| Authentication | Proof of identity sent with a request (API key, token) |
# The simplest API call — asking GitHub for a user profile
curl https://api.github.com/users/torvalds
# Returns JSON: name, followers, public repos, etc.
A real-world analogy
Think of a restaurant:
- You (the client) sit at a table and want food.
- The menu is the API — it lists what you can order and the exact wording to use.
- The waiter is the API layer — they carry your order to the kitchen and bring back the food.
- The kitchen is the server — it does the actual work (cooking), but you never go there yourself.
You don't need to know how the kitchen operates. You just read the menu (the API documentation) and place your order (make a request).
How an API request works — step by step
Client Server
│ │
│ 1. Client sends a request │
│ GET /weather?city=London │
│ ─────────────────────────► │
│ │
│ 2. Server authenticates, │
│ finds the data │
│ │
│ 3. Server sends a response │
│ { "temp": 15, "sky": "cloudy" }
│ ◄───────────────────────── │
│ │
│ 4. Client uses the data │
Most web APIs communicate over HTTP — the same protocol browsers use to load web pages. A request has:
- Method: what action to perform (
GET,POST,PUT,DELETE) - URL: where to send it (
https://api.example.com/users) - Headers: metadata (authentication token, content type)
- Body: optional data payload (for
POST/PUTrequests)
The response has:
- Status code: was it successful? (
200 OK,404 Not Found,401 Unauthorized) - Headers: metadata about the response
- Body: the actual data, almost always JSON
Types of APIs
There are several styles of APIs. Here are the most common:
| Type | Protocol | Format | Best for |
|---|---|---|---|
| REST | HTTP | JSON (usually) | Web services, most public APIs |
| GraphQL | HTTP | JSON | Flexible queries, mobile apps |
| gRPC | HTTP/2 | Protobuf (binary) | Microservices, high performance |
| WebSocket | WS / WSS | JSON or binary | Real-time: chat, live feeds |
| SOAP | HTTP / SMTP | XML | Legacy enterprise systems |
| Webhook | HTTP callback | JSON | Event-driven notifications |
REST (most common)
REST (Representational State Transfer) organises data around resources (things, like users or orders) accessed through URLs with standard HTTP methods.
GET /users → list all users
GET /users/42 → get user #42
POST /users → create a new user
PUT /users/42 → update user #42
DELETE /users/42 → delete user #42
GraphQL
GraphQL lets the client specify exactly which fields it needs — no more, no less.
query {
user(id: 42) {
name
email
posts {
title
}
}
}
A single request can fetch nested, related data from multiple resources — no extra round trips.
gRPC
gRPC uses a binary protocol (Protobuf) and HTTP/2, making it much faster than text-based REST — preferred in internal microservices.
WebSocket
WebSockets keep a persistent, two-way connection open between client and server, enabling real-time communication (stock tickers, chat apps, multiplayer games).
Reading API documentation
Every API comes with documentation. The key things to look for:
| Section | What it tells you |
|---|---|
| Authentication | How to prove who you are (API key? OAuth token?) |
| Base URL | The root address all endpoints share |
| Endpoints | Available routes and what they do |
| Parameters | What data you can pass (query params, body fields) |
| Response format | What data comes back and its shape |
| Rate limits | How many requests you're allowed per minute/day |
| Error codes | What different error responses mean |
Making your first API call
With curl (terminal)
# GET request — no authentication required
curl https://jsonplaceholder.typicode.com/todos/1
# Response:
# {
# "userId": 1,
# "id": 1,
# "title": "delectus aut autem",
# "completed": false
# }
With JavaScript (Fetch API)
// GET request
async function getUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`, {
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const user = await response.json();
return user;
}
// POST request — create a new resource
async function createUser(name, email) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name, email })
});
return response.json();
}
With Python (requests library)
import requests
BASE_URL = "https://api.example.com"
HEADERS = {"Authorization": "Bearer YOUR_TOKEN"}
# GET — fetch a resource
response = requests.get(f"{BASE_URL}/users/42", headers=HEADERS)
response.raise_for_status() # raises exception on 4xx/5xx
user = response.json()
print(user["name"])
# POST — create a resource
new_user = {"name": "Alice", "email": "alice@example.com"}
response = requests.post(f"{BASE_URL}/users", json=new_user, headers=HEADERS)
response.raise_for_status()
created = response.json()
print(created["id"]) # the ID assigned by the server
API authentication — the most common methods
Sending a request without authentication is like walking into a bank and asking for someone's account balance without showing ID. Most APIs require you to prove who you are.
| Method | How it works | Common use |
|---|---|---|
| API Key | A secret string in a header or query param | Simple server-to-server calls |
| Bearer Token (JWT) | A signed token in the Authorization header |
User-authenticated apps |
| OAuth 2.0 | A flow where users grant apps permission | "Login with Google/GitHub" |
| Basic Auth | Base64-encoded username:password in a header |
Legacy APIs, internal tools |
| HMAC Signature | Request signed with a shared secret | Financial APIs, webhooks |
# API Key in a header
GET /data HTTP/1.1
X-API-Key: sk_live_abc123def456
# Bearer Token (JWT)
GET /profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
HTTP status codes you'll encounter
2xx ─ Success
200 OK ← Standard success
201 Created ← Resource created (after POST)
204 No Content ← Success, nothing to return (after DELETE)
3xx ─ Redirect
301 Moved Permanently
302 Found (temporary redirect)
4xx ─ Client errors (you did something wrong)
400 Bad Request ← Invalid data in your request
401 Unauthorized ← No / invalid authentication
403 Forbidden ← Authenticated but not allowed
404 Not Found ← Resource doesn't exist
409 Conflict ← Duplicate or constraint violation
422 Unprocessable ← Validation error
429 Too Many Requests ← Rate limit hit
5xx ─ Server errors (the API has a problem)
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
Public APIs you can explore right now
You don't need credentials for these — great for learning:
| API | What it does | URL |
|---|---|---|
| JSONPlaceholder | Fake REST API for testing | jsonplaceholder.typicode.com |
| Open-Meteo | Weather forecasts, no key needed | open-meteo.com/v1/forecast |
| GitHub | Users, repos, issues | api.github.com |
| Cat Facts | Random cat facts | catfact.ninja/fact |
| REST Countries | Country data (population, capital…) | restcountries.com/v3.1/all |
| NASA Astronomy | Picture of the day | api.nasa.gov/planetary/apod |
# Get today's weather in London (no key needed)
curl "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12¤t_weather=true"
# Get all repos for a GitHub user
curl https://api.github.com/users/torvalds/repos
Building your own API — a minimal example
Most backend frameworks make it easy to expose your data as an API. Here's a working example in Node.js (Express) and Python (FastAPI):
Node.js / Express
import express from 'express';
const app = express();
app.use(express.json());
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
// GET all users
app.get('/users', (req, res) => {
res.json(users);
});
// GET one user
app.get('/users/:id', (req, res) => {
const user = users.find(u => u.id === Number(req.params.id));
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
});
// POST new user
app.post('/users', (req, res) => {
const { name } = req.body;
if (!name) return res.status(400).json({ error: 'name required' });
const user = { id: users.length + 1, name };
users.push(user);
res.status(201).json(user);
});
app.listen(3000, () => console.log('API running on http://localhost:3000'));
Python / FastAPI
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI() # Auto-generates /docs Swagger UI
class User(BaseModel):
name: str
users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
@app.get("/users")
def list_users():
return users
@app.get("/users/{user_id}")
def get_user(user_id: int):
user = next((u for u in users if u["id"] == user_id), None)
if not user:
raise HTTPException(status_code=404, detail="Not found")
return user
@app.post("/users", status_code=201)
def create_user(user: User):
new_user = {"id": len(users) + 1, "name": user.name}
users.append(new_user)
return new_user
Private vs Public vs Internal APIs
| Type | Audience | Examples |
|---|---|---|
| Public (Open) | Anyone | Twitter API, Google Maps, Stripe |
| Partner | Approved partners with credentials | B2B integrations |
| Private (Internal) | Only within your organisation | Your frontend calling your backend |
| Composite | Combines multiple API calls into one | BFF (Backend for Frontend) pattern |
API rate limiting
Rate limiting controls how many requests a client can make in a time window. When you exceed the limit, the API returns 429 Too Many Requests.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1720101600
Retry-After: 60
{"error": "Rate limit exceeded. Retry after 60 seconds."}
Best practices when hitting rate limits:
- Implement exponential back-off — wait, then retry
- Cache responses when the data doesn't change often
- Use webhooks instead of polling when the API supports it
- Read
Retry-Afterheaders
Common API mistakes (and how to avoid them)
| Mistake | Why it's a problem | Fix |
|---|---|---|
| Hardcoding API keys in source code | Keys leak via version control | Store in environment variables |
| Not checking status codes | Silently processes error responses as data | Check response.ok / raise_for_status() |
| Fetching more data than needed | Slow performance, wastes bandwidth | Use query params / GraphQL field selection |
| No retries on transient failures | App breaks on temporary network issues | Retry with exponential back-off |
| Ignoring rate limit headers | Gets permanently throttled or banned | Respect X-RateLimit-* headers |
| Building without caching | Re-fetches unchanged data on every request | Cache responses; use ETags / If-Modified-Since |
| No timeout set | Request hangs forever | Set connection + read timeouts |
| Storing raw API responses in DB | Schema changes break your app | Map to your own data models |
REST vs GraphQL vs gRPC — when to use which
| REST | GraphQL | gRPC | |
|---|---|---|---|
| Learning curve | Low | Medium | High |
| Over-fetching | Common | Eliminated | N/A |
| Real-time | Polling / WebSockets | Subscriptions | Bidirectional streaming |
| Type safety | Manual / OpenAPI | Schema-first | Strong (Protobuf) |
| Browser support | Native | Native | Needs proxy |
| Best for | Public APIs, CRUD | Flexible queries, mobile | Microservices, internal |
API vs SDK — what's the difference?
An API is the raw interface — URLs, methods, authentication. You call it yourself using HTTP.
An SDK (Software Development Kit) is a library that wraps an API and provides a developer-friendly interface in a specific language.
// Using the raw Stripe API directly
const response = await fetch('https://api.stripe.com/v1/charges', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.STRIPE_KEY}` },
body: new URLSearchParams({ amount: '1000', currency: 'usd', source: 'tok_visa' })
});
// Using the Stripe SDK (much easier!)
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_KEY);
const charge = await stripe.charges.create({ amount: 1000, currency: 'usd', source: 'tok_visa' });
Both do the same thing. The SDK handles authentication, error parsing, and TypeScript types automatically.
Frequently Asked Questions
Q: Do I need to learn APIs to become a developer? Yes — APIs are the backbone of modern software. Whether you're building front-end apps that talk to a backend, or backend services that call third-party tools (payment processors, email services, AI models), you'll use APIs daily.
Q: Is an API the same as a URL? No. A URL is an address. An endpoint is a URL that an API exposes to receive requests. An API is the full set of endpoints, authentication rules, and data contracts — it can have dozens or hundreds of endpoints.
Q: What is a REST API vs a regular API? "API" is the broad term — any interface for software communication. REST is a specific style of API that uses HTTP and organises data around resources. Most web APIs you encounter are REST APIs.
Q: What language should I use to call an API?
Any modern language works: JavaScript (fetch or axios), Python (requests or httpx), Go (net/http), PHP (curl), Ruby (net/http), Java (HttpClient), and many others. The API doesn't know or care which language you use — it only sees HTTP requests.
Q: What is an API key and is it safe to share? An API key is a unique identifier (usually a random string) that proves your identity to an API. Never share it publicly — treat it like a password. Never commit it to GitHub or hard-code it in client-side JavaScript that users can see. Use environment variables on the server.
Q: How do I know what an API can do? Read its documentation and use its interactive docs if available (Swagger UI, Postman collections). Most modern APIs provide an OpenAPI spec (a JSON/YAML file describing all endpoints, parameters, and responses) that you can import into tools like Postman or Insomnia.
Key takeaways
- An API is a contract that lets two pieces of software communicate without knowing each other's internals.
- Most modern web APIs use HTTP and return JSON — that's called a REST API.
- Every API call has a request (method + URL + headers + optional body) and a response (status code + body).
- Authentication (API keys, Bearer tokens, OAuth) proves who you are.
- Rate limits control how many requests you can make — always respect them.
- Read the documentation: endpoints, parameters, authentication, and error codes are all there.
The best way to learn APIs is to call a few real ones. Start with a free, keyless API like JSONPlaceholder or Open-Meteo, make some requests with curl or your favourite language, and inspect what comes back.