Skip to content
← Free FDE training guides

Free learning / 45-minute REST API lab

REST API 101: read a resource, change it deliberately

Define resources, representations and HTTP methods. Run seven local request sequences, inspect repeated operations and keep an older edit from overwriting newer work.

No account needed. Use your own copy for writing and keep the original as a reference.

Engineering lab library / Run locally

See what the request actually changes

Predict statuses and state changes, then inspect the actual exchanges. Change one cause at a time and explain why a new version tag does not fix an old intent.

Real HTTP on a temporary loopback port, with fictional in-memory tickets. No model, authentication, external service or persistent storage; this is a local teaching server.

  1. Start here / Python 3.11+ · Standard library

    REST resource lifecycle · local HTTP

    Compare actual reads, creations, replacements and deletions; inspect stale and missing conditions.

    Python 3.11+ standard library · Loopback only · Fictional tickets

An original 45-minute lesson for engineers who know functions and records but are new to web API design. Define the pieces, follow the diagram, predict seven exchanges, then inspect actual HTTP and state changes. All tickets are fictional.

1. Give each piece a different job

An API is a software interface: the operations, inputs, outputs and errors that a caller can rely on. REST, Representational State Transfer, is an architectural style for networked applications. It organizes interactions around resources and a uniform interface. It is not a programming language, product or synonym for returning JSON.

Think of a ticket as a record behind a service. /tickets/T-104 identifies it. The JSON you receive is a representation of that resource. It need not expose every internal database field. HTTP carries the request and response; JSON is the data format chosen here. FastAPI is one Python framework for implementing such a service. This lab uses Python's standard library so you can inspect the exchange without installing a framework.

PieceIn our fictional serviceFamiliar comparison
ResourceTicket T-104A record with an identity
Address/tickets/T-104The reference used to find the record
Representation{"title":"Pump check","status":"open"}A public view of the record
MethodGET, POST, PUT or DELETEThe requested operation
ResponseStatus, headers and sometimes a bodyA result with explicit metadata

The function-call analogy has a limit: a remote call can fail after the service has performed work. A caller must reason about what it observed, not assume that a missing response means nothing happened. An FDE designing an agent tool needs to distinguish reading a ticket from creating or replacing one before giving a model access to that tool.

REST also includes client/server separation, stateless requests, cache rules, layering and a uniform interface, including hypermedia controls; code on demand is optional. This small lab teaches resource interactions and HTTP semantics, not every REST constraint. Stateless requests do not forbid a server from storing tickets. The server still needs authentication and authorization in a real system; a method, identifier or version tag supplies none of those.

2. Read the method before repeating the call

MethodOur contractWhat to predict on repetition
GET /tickets/T-104Read the current representationNo requested business mutation
POST /ticketsCreate a new ticket; return its address in LocationTwo submissions can create two tickets
PUT /tickets/T-104Replace the complete writable representation, if its version still matchesSame intended effect; a repeated condition may now fail
DELETE /tickets/T-104Remove this resourceIt stays absent; response statuses can differ

Safe describes a method whose requested semantics are read-only. Logging a GET is possible; silently dispatching a technician on GET violates the read contract. Idempotent means identical requests have the same intended effect as one request. It does not promise identical responses or that replaying an old intent is always appropriate after another person's edit. GET, PUT and DELETE are idempotent by HTTP semantics; POST has no general replay guarantee.

The lab's PUT replaces title and status. Sending just status is refused instead of silently treating PUT as a partial update. PATCH is another HTTP method for a defined patch document; it is not implemented here, and whether a particular patch is idempotent depends on its operation.

An ETag, or entity tag, identifies a representation version chosen by the service. It is an opaque value: copy it exactly rather than deriving one from an integer you guessed. The If-Match request header says to perform this change only if the current representation matches the supplied tag. Our narrow contract accepts one strong tag returned by GET. It does not implement tag lists, wildcards, cache validation or the rest of HTTP's conditional syntax.

UNDERSTAND THE SYSTEM

One resource, different operations

REST is an architectural style; HTTP carries the exchange. An ETag labels a representation version. If-Match asks the service to change it only if that version still matches. Follow fictional tickets through the local lab cases; this diagram explains the exchanges, rather than running a server in your browser.

FOLLOW ONE EXAMPLE

See what moves and why.

Authored illustration
01 / EXPLORE THE PARTSTap a part to explain it
Direction of information or workReturn / feedback

WHAT THIS PART DOES

Calling application

The application chooses a read or change and retains the representation it reviewed. A model proposal cannot supply its own authority.

CONNECTED TO
  • Prepare: HTTP request
  • Reconcile: Client decision
Read the connections in plain English
  1. 01
    Calling application → HTTP request

    Select the operation and the exact representation the caller intends to send.

  2. 02
    HTTP request → Service checks

    The local client sends actual HTTP to the service.

  3. 03
    Service checks → Resource state

    Only accepted operations alter the ticket. Rejected writes preserve the existing state.

  4. 04
    Resource state → HTTP response

    The service reports the result of the read, mutation or refusal.

  5. 05
    HTTP response → Client decision

    The client compares the response to its intended work and the documented contract.

  6. 06
    Client decision → Calling application

    Before another edit, inspect the current representation and reconcile the intended change.

Check your understanding: Does fetching a fresh ETag automatically make an old edit correct?

No. The tag guards a version comparison. The caller must inspect the current content and reconcile the intended change. In the lab's second edit, refreshing only the tag lets an old body overwrite the other editor's title.

3. Predict and run seven exchanges

Download fde-rest-resource-lab.py into your practice folder. Python 3.11+ is enough; there are no packages, accounts or credentials to configure. The program starts a short-lived service on a randomly assigned 127.0.0.1 port, makes real local HTTP requests, and closes it. It never binds to a public interface, contacts an external service or writes ticket data to disk. Use fictional data. Python's teaching HTTP server is not a production deployment template.

Code example
python3 --version
python3 fde-rest-resource-lab.py compare
python3 fde-rest-resource-lab.py stale-edit

Before running, write the statuses and final ticket state you expect. Each case starts from its own T-104 with title Pump check, status open and ETag "T-104-v1". Each trace records the request, response and a teaching-only inspection of server state. A real client normally cannot inspect that last field; it needs the service's documented read or reconciliation interface.

CaseExpected status sequenceState to inspect
read200, 200Same one ticket and same ETag
create-repeat201, 201New T-105 and T-106, each with its own Location
replace-repeat200, 200, 412GET, then two identical conditional PUTs; T-104 stays queued at v2
delete-repeat204, 404T-104 is absent after both DELETEs
stale-edit200, 200, 412, 200Another editor's title and queued status survive the stale PUT
missing-precondition428No change; the required If-Match header was absent
partial-replacement200, 400No change; the complete writable representation was not supplied

200 means this request succeeded. 201 identifies creation; inspect Location. 204 has no response body. 404 says this resource was not found in this lab. 400 rejects our malformed representation. 412 means the condition did not hold. 428 means this service requires a condition; not all services enforce that rule. Read the specific contract rather than assuming every error is retryable.

4. Follow the edit that arrived too late

The stale-edit case models two callers in a deliberate sequential order. It is not a concurrent-load test:

  1. Editor A reads T-104 at v1 and prepares to close it with the original title.
  2. Editor B replaces it with Pump check: reviewed scope, status queued, using v1 in If-Match. The response is 200 and the new representation is v2.
  3. Editor A sends the older full representation with v1. The server compares the tag before mutation, returns 412 and keeps B's representation.
  4. A fresh GET shows B's title and queued status. A must compare the changes and decide what is still intended before sending another update.

Read dispatch in the program. Find the validation, missing-condition and mismatched-condition branches before row["body"] = raw. The exact submitted JSON bytes are stored and returned; the ETag sits in a response header, not in a field the caller can overwrite. There is no login or permission check in this fictional local service. Version checking and authorization are different jobs.

In replace-repeat, the first PUT changes v1 to v2. The second identical request still carries v1, so it receives 412 while the resource remains queued. Different statuses do not disprove idempotency. They also do not prove who performed an earlier change. After uncertain delivery, read/reconcile according to the service contract instead of declaring the operation failed or blindly resending with a new tag. This lab does not simulate a network timeout or implement transactional idempotency keys.

5. Change one cause at a time

Make two separate copies. Keep the reference file unchanged.

Experiment A — count creations. In one copy, change CREATE_ATTEMPTS = 2 to CREATE_ATTEMPTS = 1. Run create-repeat. There should be one 201, one Location and just one new ticket. The original two creations were actual server mutations, not repeated display of the same result. A caller-generated key would need an explicit server-side deduplication contract; merely adding an undocumented header cannot establish one.

Experiment B — expose a misleading repair. In the other copy, set REFRESH_BEFORE_SECOND_EDIT = True and run stale-edit. The code gets a fresh ETag but resends A's old body without reconciling it. Expect statuses 200, 200, 200, 200, 200 and final title Pump check, status closed, v3. B's reviewed title was overwritten. This is a deliberately flawed client strategy in the local exercise, not the recommended repair.

Explain why the server's condition passed. It verifies that the submitted tag matches now; it cannot tell whether A actually reviewed the current content. Write a better client sequence: read current content, compare with the original, reconcile the intended change, then submit the reviewed representation with the matching tag. A new 412 should restart that review instead of forcing a write.

6. Turn the API into an agent tool contract

An agent proposes closing T-104 after reading v1. While it is thinking, a human changes the scope. Sketch the components: model proposal → application policy → HTTP client → resource service → observed result. State who owns each check.

Produce a short contract with:

  • A read-only tool separate from the write tool, with explicit allowed fields.
  • Trusted caller and resource authorization outside model-generated arguments.
  • A version tied to the representation that was actually reviewed.
  • A 412 path that returns for reconciliation, a 428 configuration repair and an uncertain-delivery path that preserves an unknown outcome.
  • A distinction between receiving a 2xx response and completing the customer's intended work. Changing a ticket record does not prove a technician was sent.

Discuss one new deployment boundary: TLS, identity, durable storage, atomic compare-and-update, auditing, request limits or crash recovery. The sequential in-memory lab has not established these. Choose the smallest test that would show the boundary you are proposing, using an isolated environment.

7. Keep the evidence and go deeper

Keep seven predictions and observed traces, both controlled edits, your repaired client sequence and the agent tool contract. A useful explanation names the resource, representation, operation, observed state and remaining uncertainty.

Continue with the first FastAPI request to see a framework route and validate the input. Use networking 101 for connection boundaries, and action recovery for the harder case where a response is lost after an external effect.

Primary references checked 21 October 2026:

Before you move on

Keep the evidence of your work.

  • Seven predictions compared with actual HTTP exchanges and resource states.
  • Two controlled edits and a repaired content-reconciliation sequence.
  • A read/change tool contract with authority and uncertainty made explicit.

Keep these in your own working copy. Reading this page does not save work or record completion.

Suggested next free session

Cloud networking 101: read an address plan

Understand destination ranges and route choices before diagnosing the connection. This is a suggested sequence; choose the practice that addresses your current gap.

Open the next free guide
Have Academy access?

Continue with worked explanations, practice and review in the related lesson.

Open the related Academy lesson →
Back to top ↑