7 routes42 sections324 units

Unit 4.8 · about 5 h

26 / 324

HTTP APIs, pagination, streaming and idempotency

Retries are normal and duplicates are corruption. Validation plus status codes make failures legible, pagination bounds the response, and idempotency keys make a retried request safe to repeat.

  • explain
  • implement

You can now

  • Expose the service over HTTP with request validation, response filtering, correct status codes and typed errors.
  • Ship capped limit-offset pagination and one streaming endpoint with bounded pages.
  • Implement idempotency keys so retried POSTs return the stored response with a single side effect, and mismatched replays error.

Covers

  • HTTP methods, validation, status codes, pagination and streaming
  • Idempotency keys, duplicate replay and side-effect ownership

Study, in this order

8 steps

  1. Request Body
    FastAPI tutorial

    Create your data model; Declare it as a parameter; Results; Use the model

  2. Handling Errors
    FastAPI tutorial

    Use HTTPException; Install custom exception handlers; Override request validation exceptions

  3. Response Model
    FastAPI tutorial

    Return the same input data (the leak); Add an output model; Return Type and Data Filtering

  4. Response Status Code
    FastAPI tutorial

    Changing the default, with 201 for creates; Shortcut to remember the names

  5. Query Parameters: `skip` and `limit`
    FastAPI tutorial

    Defaults: skip 0, limit 10 and the slice

  6. Numeric validations for a page cap
    FastAPI tutorial

    Number validations: greater than and less than or equal (ge and le work the same on Query, which is how limit gets a cap)

  7. Stream JSON Lines
    FastAPI tutorial

    Stream JSON Lines with FastAPI: yield items from a function returning AsyncIterable[Item] (added in FastAPI 0.134.0); Non-async path operation functions; No Return Type

  8. Idempotent requests
    Stripe idempotent requests

    Idempotency-Key header with V4 UUID keys up to 255 characters; for API v1 the status code and body are saved once endpoint execution begins and replayed on retry, including 500s, while validation failures and concurrent conflicts save nothing; parameter-mismatch errors; keys on POST, never GET or DELETE; keys pruned after at least 24 hours

Focus on

  • One Pydantic model per request, one output model per response. Invalid bodies fail with 422 before any business logic runs.
  • The output model strips secrets: returning the input model leaks fields. Create returns 201, unknown ids return 404 with the detail envelope.
  • Defaults alone do not bound a page: a client can still send limit=1000000. Cap it with Query(le=...) so oversized requests fail with 422. Streams yield items under a declared AsyncIterable[Item] return type so validation and docs still apply.
  • The idempotency ledger stores, per key, the endpoint, a hash of the params and the saved response. A replay with the same hash returns the saved response; the same key with a different hash errors. Keys belong on POST: GET and DELETE are idempotent by definition.

Reproduce closed-book

Closed-book, build a create endpoint with an output model, a capped paged list and an idempotency-key ledger: show 201 with secrets stripped, 422 on a bad body and on an oversized limit, 404 on an unknown id, a bounded page slice, and a double POST with one key producing one stored object.

Traps

  • Returning the input model. Extra fields and secrets serialize to the client; a separate output model filters them, verified with TestClient on FastAPI 0.143.
  • Same idempotency key with new params silently accepted. Compare params and return a conflict, or a retry becomes an overwrite.
  • Check-then-insert on the ledger. Two concurrent first attempts both miss the lookup and both run the side effect; claim the key with a unique insert first, and answer a concurrent duplicate with a retryable conflict.

Practice

FastAPI tutorial Testing: extended example

Testing extended example: extended app file plus extended testing file, Run it

In that style, write replay, mismatch and oversized-limit tests for your keyed endpoint plus a pagination slice test, swapping the key store with app.dependency_overrides (Advanced User Guide: Testing Dependencies with Overrides).

Self-test

  1. A POST body misses a required field. What status, and when does business logic run?

  2. A client POSTs twice with the same key after a network timeout. How many objects exist and what does the second response carry?

  3. The same key arrives with different params. What happens?

  4. GET /items would return 100000 rows. What breaks and what is the fix?

Completion criterion

Stop when

TestClient shows 201 filtered, 422 on a bad body and an oversized limit, the 404 detail envelope, a bounded page, and a keyed double POST with one side effect plus a mismatch conflict.

Mark passed, then open 5.1 Only mark this when you can do it without notes.

Leads to

Comes after

Resources for this unit

  • FastAPI tutorial
    FastAPIsupportimplementation
    Use Request Body, Dependencies, Handling Errors and Testing to expose the same service layer through HTTP. Keep framework models outside the domain core and preserve the same error semantics as the CLI.
  • Stripe idempotent requests
    Stripesupportreference
    Use the Idempotency-Key header contract, stored-response replay, parameter-mismatch errors and POST-only scope to implement keyed replay for one endpoint.

Also in this section

  • Official docs typed-service build path
    Python typing, Pydantic, FastAPI and PostgreSQLprimarycourse
    Build one record service in this order: structural protocols and generics; Pydantic models, validators, strict mode, serialization and settings; FastAPI request bodies, dependencies, errors and tests; then PostgreSQL transactions and EXPLAIN. Replay valid, malformed, duplicate and previous-schema requests through CLI and HTTP.
  • AlgoMaster SQL - selected route
    AlgoMasterrequiredcourse
    Study SQL Foundations, Querying Data, Joins, Subqueries and CTEs, Window Functions, DDL, DML and Views, Performance Optimization, Transactions and Concurrency, and Data Modeling. Stop when the service queries and transaction tests pass.
  • PostgreSQL transactions and EXPLAIN
    PostgreSQLrequiredreference
    Use the transaction tutorial and EXPLAIN guide to demonstrate commit, rollback, one isolation anomaly or prevented anomaly, and a measured plan improvement on the database actually used.
  • AlgoMaster Low-Level Design - one rehearsal
    AlgoMastersupportpractice
    Use one fitting design prompt to rehearse interface contracts, dependency direction and failure ownership. Treat the review as feedback, then verify behavior with your own tests.
  • Stas' Python Cookbook - data and interfaces
    Stas Bekmansupportreference
    Use Serialization and Deserialization plus Environment and Arguments for focused implementation help. Compare JSON, JSONL, CSV and compressed data, and never use pickle for untrusted interchange.
  • AlgoMaster Python - interfaces, generics and data files
    AlgoMastersupportcourse
    Use Interfaces and Protocols plus Generic Types for structural typing, and Working with JSON plus Working with CSV for JSONL, error handling, newline and DictReader behavior. Lesson quizzes check recall; implementation is verified with your own scripts.
  • SQLAlchemy 2.1 documentation - select, Session and eager loading
    SQLAlchemyreferencereference
    Use the select() tutorial for 2.x query style, Session basics for the transaction boundary and identity map, and relationship loading for lazy versus selectinload versus joinedload plus raiseload. Use select() style and Session.execute or Session.scalars only, never the legacy Query API.
  • Alembic tutorial - migration scripts and downgrading
    SQLAlchemysupportreference
    Use Create a Migration Script, Running our First and Second Migration, Getting Information and Downgrading to run a paired upgrade and downgrade round trip on a scratch database.
  • PyArrow Parquet read and write docs
    Apache Arrowsupportreference
    Use Reading and Writing Single Files plus Table from_pydict and from_pylist to convert normalized records to Parquet and test types, nulls, column projection and schema.

Quick find

Search Michi

Type to search every route, section, unit, topic and resource.

Enter opens the first result Esc closes

Reference

Keyboard shortcuts

n
Continue to the first unit not passed
j / k
Next / previous unit
1 2 3
Toggle learned, practised, passed
/
Open search
?
Show this help
Esc
Close open panels