CodingNic

REST APIs with FastAPI

REST fundamentals

REST APIs with FastAPI 20 min read

REST fundamentals

REST fundamentals

Lesson 0 introduced APIs in the broadest sense — servers that hand out JSON instead of HTML. That mental model is enough to get started, but it leaves an obvious question unanswered.

How do you actually design one?

If you’re building an API for tasks, do you call it /getAllTasks, /tasksAll, /task-list, /api/tasks/list, or just /tasks? Do you write a separate URL for every action, or use the same URL with different verbs? When you create a task, where does it go? When you delete one, what should the server send back?

These aren’t matters of personal taste. There’s a widely-followed set of conventions called REST, and once you’ve internalised the rules, the answers to most “how should I design this endpoint?” questions become obvious. This lesson is about those conventions.

No code yet. We need the design vocabulary firmly in place before we start writing routes — otherwise the first FastAPI app you build (next lesson) won’t have anywhere to stand.


What REST is

REST stands for Representational State Transfer, a phrase coined by Roy Fielding in his 2000 doctoral thesis. The name is academic and unhelpful; the ideas are not. Strip them down to plain language and you get a handful of conventions:

  1. Organise your API around resources — the nouns of your domain (tasks, users, books, orders).
  2. Use URLs to identify resources — /tasks for the collection, /tasks/42 for an individual.
  3. Use HTTP methods to express actions — GET to read, POST to create, PUT/PATCH to update, DELETE to remove.
  4. Use HTTP status codes to communicate outcomes — 200 for success, 404 for “not found,” 400 for “bad request,” and so on.
  5. Keep requests stateless — every request carries everything the server needs to handle it. The server doesn’t remember what happened on the previous request.

An API that follows these rules is called a RESTful API. Almost every public web API you encounter — GitHub’s, Stripe’s, Spotify’s, Twitter’s — is RESTful (or close enough). The conventions are the lingua franca of web APIs.

We’ll unpack each idea in turn.


Resources are nouns

The single most important shift when designing a REST API is this: organise your endpoints around the things your app deals with, not the actions people perform on them.

Imagine a task management app. The wrong way to design URLs:

text
/createTask
/getTask
/getAllTasks
/updateTask
/deleteTask
/markTaskComplete
/listOpenTasks

Every URL is a verb. Every action gets its own endpoint. You end up with dozens of URLs, no consistency, and no way to predict what /searchOpenTasksByDueDate is going to be called.

The RESTful way:

text
/tasks
/tasks/42

That’s it. Two URL patterns. The first refers to the collection of tasks. The second refers to task number 42, specifically. The action — read, create, update, delete — is communicated by the HTTP method, which we’ll get to next.

This pattern scales. A blog might have /posts, /posts/123, /comments, /comments/7. A user management API might have /users, /users/42, /users/42/roles. Once you see the pattern, every new resource fits the same shape.

A few rules of thumb that hold up in practice:

  • Use plural nouns for collections: /tasks, not /task. The plural is more honest about the shape — you’re accessing a list, and individual items live inside the list.
  • Use IDs to identify members: /tasks/42. Never embed business-logic queries in the URL itself.
  • Nest resources only when they’re truly owned: /users/42/tasks is fine if tasks belong to users. /users/42/profile/settings/notifications/email is not — too deep, too brittle.

HTTP methods are the verbs

Now that the URLs are nouns, where do the actions go? Into the HTTP method of the request.

Every HTTP request has a method (sometimes called a verb): GET, POST, PUT, PATCH, DELETE. These existed long before REST — your browser uses them every day. REST just gives them specific meanings in an API context.

HTTP methods for REST APIs

Walk through each one:

GET — read data

GET requests fetch data without changing anything on the server. Two common shapes:

  • GET /tasks — return all tasks (probably as a JSON array).
  • GET /tasks/42 — return one task by ID.

A GET request never has a body. Any parameters go in the URL itself, usually as query strings (/tasks?status=completed&limit=10) — we’ll cover that in Lesson 4.

The crucial property: GET is safe. Calling GET /tasks ten times in a row should change nothing. The server might return slightly different data each time (if other people are adding tasks), but the act of asking doesn’t change state.

POST — create new data

POST requests create new resources. The URL points at the collection; the request body describes the new item.

text
POST /tasks
body: { "title": "Buy groceries", "due_date": "2026-06-01" }

The server creates a new task, assigns it an ID, and (conventionally) returns the newly-created object — usually with status code 201 Created.

POST is not safe. Calling it twice creates two tasks. We’ll see this matter when we talk about idempotency in Lesson 12.

PUT — replace data

PUT updates an entire resource by replacing it. You send the whole object, including any unchanged fields, and the server overwrites the existing row.

text
PUT /tasks/42
body: {
  "title": "Buy groceries",
  "completed": true,
  "due_date": "2026-06-01"
}

Even if you only meant to change completed, you have to send all the fields. That’s the “replace” semantic — the server treats the body as the new, full state of the resource.

PATCH — modify part of data

PATCH is the surgical update. It sends only the fields that should change.

text
PATCH /tasks/42
body: { "completed": true }

The server reads 42, applies the change, and leaves the other fields untouched.

In practice, most APIs use PATCH for nearly all updates and rarely use PUT. Sending less data is cheaper and avoids accidental overwrites — if two people are editing the same record, a PATCH is less likely to clobber the other’s changes.

If you only learn one of PUT / PATCH, learn PATCH. It’s more useful day-to-day.

DELETE — remove data

DELETE removes a resource.

text
DELETE /tasks/42

No request body needed — the URL already says which thing to delete. The server confirms the deletion and (conventionally) returns status code 204 No Content, which we’ll come back to in a moment.


The same URL, different methods

Here’s where REST’s pattern starts to feel elegant. Look at all the things you can do with the single URL /tasks/42:

Method Effect
GET Fetch task 42
PUT Replace task 42 entirely
PATCH Update some fields of task 42
DELETE Delete task 42

Four different operations, one URL. The URL says which resource; the method says what to do with it. No more /createTask, /updateTask, /deleteTask — they collapse into a clean, predictable shape.

You’ll see this pattern again and again. Every well-designed REST API uses it.


Status codes communicate outcomes

When you build HTML web apps, the standard “everything worked” response is to return a page and let the user see for themselves. APIs don’t have that luxury — the caller is another program, and the program needs an unambiguous signal about whether the request succeeded.

That’s what HTTP status codes are for. Every response carries a three-digit code. The first digit gives the broad category:

  • 2xx — success. It worked.
  • 3xx — redirection. Look somewhere else. (Rare in APIs.)
  • 4xx — client error. You sent something wrong.
  • 5xx — server error. We did something wrong.

The specific codes you’ll use most:

Code Name When to use it
200 OK Successful GET, PUT, or PATCH
201 Created Successful POST that created a new resource
204 No Content Successful DELETE — nothing to return
400 Bad Request The request was malformed (missing field, wrong type)
401 Unauthorized The caller isn’t signed in / didn’t provide credentials
403 Forbidden The caller is signed in but isn’t allowed to do this
404 Not Found The resource doesn’t exist
409 Conflict Tried to create something that already exists (e.g. duplicate email)
422 Unprocessable Entity Validation failed — wrong data, even if syntactically correct
500 Internal Server Error Something blew up on the server

You don’t need to memorise all of them. Notice the pattern: 2xx means “fine,” 4xx means “your fault,” 5xx means “my fault.” That alone is enough to read most API responses.

A few subtleties worth knowing:

  • 200 vs 201. Both mean success. 201 specifically signals “I created something new” — used for POST responses. Use 200 for everything else successful.
  • 204 is “success, but nothing to send back.” Common after DELETE — the resource is gone, what would you return? 204 says “operation succeeded, body is intentionally empty.”
  • 401 vs 403. 401 means “I don’t know who you are.” 403 means “I know who you are, and the answer is no.” The distinction matters: 401 usually means “go log in”; 403 means “you can’t do this even if you log in again.”
  • 400 vs 422. Both mean the client sent bad data. 400 is for malformed requests (broken JSON, missing required fields at the structural level). 422 is for valid requests with semantic issues (the JSON parses fine, but the email isn’t an email). FastAPI uses 422 for Pydantic validation errors automatically.

FastAPI handles many of these for you, but you’ll also set them explicitly on certain responses. We’ll come back to status codes in Lesson 8 when we’re building the Books API.


Statelessness

The last REST principle is short but worth naming.

Every request must contain everything the server needs to handle it.

Concretely: the server should not rely on remembering the previous request, the previous session, or any kind of conversation state. If a request needs to know who the user is, it carries an authentication token. If a request needs to know which page of results to return, the URL says so (?page=3). Nothing is implicit.

This sounds restrictive but it’s a major reason APIs scale so well. A stateless server can handle a million users across a hundred servers, because no single server needs to “remember” any client. Any server can handle any request.

This is also exactly the JWT model we covered in Module 5, Lesson 10. The client carries identity in a token; the server validates it; no shared session state is required. Sessions and cookies (which we used everywhere in Module 5 except the JWT lesson) are technically a form of state, but they’re tolerated because the state is just a lookup key — the bulk of the conversation still lives in the request.

If you’re building a strictly RESTful API for mobile clients or microservices, you’ll likely use tokens, not cookies. If you’re building an API consumed by your own browser frontend, sessions are pragmatic and fine. We’ll cover both flavours later in the module.


A worked example: the tasks API

Pulling it all together — what would a complete REST API for tasks look like? Here’s the standard shape:

Method URL What it does Typical response
GET /tasks List all tasks 200 OK + array of tasks
POST /tasks Create a new task 201 Created + the new task
GET /tasks/42 Fetch task 42 200 OK + one task
PATCH /tasks/42 Update some fields of task 42 200 OK + the updated task
PUT /tasks/42 Replace task 42 entirely 200 OK + the updated task
DELETE /tasks/42 Delete task 42 204 No Content

Six lines. That’s the entire CRUD interface for a resource. If you’ve designed one REST API, you’ve roughly designed them all — books, users, comments, anything. The shape doesn’t change.

You’re going to write something very close to this table by the end of Lesson 8. The point of this lesson is that you can read it right now and predict, before any code is written, what each endpoint should do.


What REST isn’t

A few things people often expect REST to be that it isn’t:

  • REST doesn’t require JSON. You can return XML, HTML, or any other format. JSON is just the most popular choice today.
  • REST isn’t a Python thing. Or a Flask thing. Or a FastAPI thing. It’s protocol-level — these are conventions for how to use HTTP, independent of language or framework.
  • REST isn’t strictly enforced. Real-world APIs bend the rules constantly. You’ll see endpoints like POST /tasks/42/complete (a verb in the URL!) in major APIs because sometimes the “right” REST design is awkward. Treat REST as a strong default, not a religion.
  • REST isn’t the only option. Alternatives like GraphQL, gRPC, and tRPC exist, with different trade-offs. They’re outside this module’s scope, but you should know they exist.

The goal is APIs that other developers can understand without reading your docs. REST is the most widely-known convention for getting there.


Summary

  • A REST API organises endpoints around resources (nouns) and uses HTTP methods (verbs) to describe actions.
  • URLs identify the thing; methods say what to do with it.
  • The five core methods: GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE (remove).
  • Status codes communicate outcomes: 2xx success, 4xx client error, 5xx server error.
  • The most-used codes: 200, 201, 204, 400, 401, 403, 404, 422.
  • Statelessness — every request stands alone. The server doesn’t remember conversations.
  • A standard CRUD resource is six endpoints around one URL pattern. Memorise the shape.

Outcome

You now know the design language of web APIs. You can look at a URL like PATCH /tasks/42 and immediately know what it’s supposed to do, and you can sketch the endpoints for a new resource without thinking hard about it. Next lesson, we put it into practice — installing FastAPI, writing your first route, and seeing the magical /docs page that comes free with every FastAPI app.