REST APIs for beginners: what every junior developer needs to know

Almost every software internship today involves working with REST APIs, calling them, building them, or both. The basics are simpler than the jargon makes them sound. This guide gets you from "I've heard of HTTP" to "I can confidently work with API endpoints in any codebase" in one read.

The one-paragraph version

A REST API is a way for one program to ask another program for data. The first program sends an HTTP request, a message with a URL and a verb (GET, POST, etc.). The second program does something (read the database, send an email, etc.) and sends back an HTTP response with a status code and a body of data, usually in JSON. That's it. Everything else is pattern, convention, and edge cases.

The five HTTP verbs you'll use 99% of the time

HTTP verbs (also called "methods") describe the kind of action you're requesting. There are nine total, but five do almost everything:

VerbWhat it meansExample
GETRead dataGet a user's profile: GET /users/42
POSTCreate dataCreate a new user: POST /users
PUTReplace dataReplace user 42 with new data: PUT /users/42
PATCHUpdate part of dataChange just the email: PATCH /users/42
DELETEDelete dataDelete user 42: DELETE /users/42

Mostly the verb is just a hint, under the hood, all five do roughly the same thing (send a message to a server). The convention exists so other engineers reading your code know what an endpoint does without reading the implementation.

URLs as nouns: the REST naming convention

The "REST" style is to make URLs nouns (resources) and use verbs to express actions on them. So:

GET    /users          → list all users
GET    /users/42       → get user 42
POST   /users          → create a new user
PATCH  /users/42       → update user 42
DELETE /users/42       → delete user 42

GET    /users/42/posts → list posts owned by user 42
POST   /users/42/posts → create a new post for user 42

Notice URLs don't say what to do, the verb says that. This is why URLs like /getUsers or /createUser are considered un-RESTful: the verb belongs in the HTTP method, not the path.

Most APIs aren't 100% RESTful in practice (every codebase has at least one POST /search or POST /login endpoint), but the pattern is the default to follow.

The HTTP status codes you actually need to know

Status codes are three-digit numbers the server sends back. There are dozens, but you'll see roughly ten in practice:

2xx: success

4xx: client error (you sent something wrong)

5xx: server error (the server broke)

The most important distinction: 4xx means the client (browser, mobile app, other server) made a mistake. 5xx means the server made a mistake. As a developer, 5xx errors are your problem; 4xx errors are usually the caller's problem (or your validation logic).

The anatomy of a request and response

An HTTP request has four pieces:

POST /api/users HTTP/1.1               ← method + path + protocol
Host: api.example.com                  ← which server
Content-Type: application/json         ← header: what the body contains
Authorization: Bearer eyJhbGc...       ← header: who's asking
                                       ← (blank line)
{"name": "Alice", "email": "a@b.com"}  ← body

And a response has the same shape:

HTTP/1.1 201 Created                   ← protocol + status code + status text
Content-Type: application/json         ← header: what the body contains
                                       ← (blank line)
{"id": 42, "name": "Alice", "email": "a@b.com"}

You almost never type these out by hand, your HTTP client (axios, fetch, requests) builds them for you. But understanding the structure helps when you're debugging "why is this request failing?"

Calling an API from JavaScript and Python

The two languages you're most likely to use as an intern. Here's a GET and POST in each:

JavaScript (with fetch)

// GET
const res = await fetch('https://api.example.com/users/42');
const user = await res.json();

// POST with JSON body
const res = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({ name: 'Alice', email: 'a@b.com' }),
});
if (!res.ok) {
  throw new Error(`HTTP ${res.status}`);
}
const newUser = await res.json();

Python (with requests)

import requests

# GET
res = requests.get('https://api.example.com/users/42')
res.raise_for_status()  # raises on 4xx/5xx
user = res.json()

# POST with JSON body
res = requests.post(
    'https://api.example.com/users',
    json={'name': 'Alice', 'email': 'a@b.com'},
    headers={'Authorization': f'Bearer {token}'},
    timeout=10,
)
res.raise_for_status()
new_user = res.json()

Notice in Python you pass json= and the library serializes for you. In JavaScript you have to JSON.stringify manually and set Content-Type: application/json. Common bug for beginners: forgetting the header and getting a 400.

Authentication: the 80/20

Most APIs need to know who you are. The two most common approaches you'll encounter:

Bearer tokens (most common modern API)

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

The client sends a token in the Authorization header on every request. The server validates the token and figures out who the user is. The token is usually a JWT (JSON Web Token), encoded user info signed by the server so it can't be forged.

API keys

Authorization: Bearer sk_test_4eC39HqLyjWDarjtT1zdp7dc
# or sometimes:
X-API-Key: sk_test_4eC39HqLyjWDarjtT1zdp7dc

A long random string that identifies the caller. Used for server-to-server APIs (like calling Stripe from your backend). Rotate them if leaked.

Cookies (web apps)

The browser automatically sends a session cookie with every request after login. Common in traditional web apps; less common in modern React/mobile clients.

Whatever the API uses, the rule is the same: never put credentials in your code or commit them to Git. Read them from environment variables.

Practice debugging API bugs without breaking real APIs

InternQuest's API track gives you 22 broken backend endpoints, wrong status codes, missing validation, IDOR vulnerabilities, missing auth. Each is a Jira ticket with an automated reviewer. Free.

Try an API mission →

JSON: the format you'll work with all day

Almost every modern API speaks JSON. The structure is:

{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com",
  "active": true,
  "tags": ["beta", "premium"],
  "address": {
    "street": "123 Main St",
    "city": "Vancouver"
  },
  "lastLogin": null
}

Six types: string, number, boolean, null, array, object. No comments. Quotes around keys are mandatory. Trailing commas are forbidden (this trips up everyone who edits JSON by hand).

Edge cases that bite beginners:

Query parameters, path parameters, body parameters

Three places to put data in a request, and they each mean something different:

Path parameters

GET /users/42

The 42 is in the URL path. Use for identifying which resource. Required, always.

Query parameters

GET /users?role=admin&limit=50

After the ?. Use for filtering, sorting, pagination, modifiers to a list request. Always optional.

Body parameters

POST /users
Content-Type: application/json

{"name": "Alice", "email": "a@b.com"}

JSON in the request body. Use for the actual payload of a POST / PUT / PATCH. Don't put body data on a GET, it's allowed by spec but breaks caching and most clients won't send it correctly.

How to debug an API call that isn't working

The two-tab approach:

  1. Open the browser DevTools Network tab (F12 → Network). Click the failing request. You see the URL, method, headers, body, status code, and response.
  2. Reproduce in curl or Postman. If it fails the same way outside your app, the bug is in the API or your request. If it works there but not in your app, the bug is in how your code constructs the request.

curl example for a POST:

curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name": "Alice"}'

Most "API bugs" are actually:

REST vs. GraphQL vs. RPC: a one-paragraph orientation

You may hear about other API styles:

REST is still the most common style by far. Learn it first; the others build on the same foundations.

The mindset to bring to API work

Three principles that turn most "API bugs" into non-issues:

  1. Validate on the server, always. Never trust the client. Every input that goes to the database should be validated.
  2. Return precise status codes. 400 for bad input, 401 for missing auth, 403 for forbidden, 404 for missing, 500 only for actual server errors. Don't return 200 with an error message in the body.
  3. Don't change response shapes mid-flight. If clients depend on a field, it has to stay. Versioned endpoints (/v1/users, /v2/users) are how you evolve safely.

That's the whole foundation. Everything else, pagination strategies, idempotency, rate limiting, OpenAPI specs, builds on top.

Practice on broken APIs in a real codebase

InternQuest's missions include backend API bugs across Express, Flask, and FastAPI, wrong status codes, missing auth, SQL injection, IDOR. Each comes with a Jira ticket and an automated reviewer. Free, no setup.

Try an API mission →