Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How to Evaluate an API

“Best” is not a property of a crate. It is a judgment about how well a representation supports its consumers' work.

Evaluation rubricEvidence conventionsReading method

This guide studies exemplary API decisions, not flawless libraries. A crate can make one difficult task feel natural while retaining awkward historical corners elsewhere. The useful question is narrower:

For this consumer task, what does the API make clear, easy, difficult, or impossible—and what does that choice cost?

The evaluation lenses

Every specimen and deep dive uses the same lenses.

LensQuestion
RepresentationDo the public types correspond closely to the problem’s concepts?
LegibilityCan a reader predict the operation from the call site?
ValidityWhich invalid states or transitions cannot be expressed?
FailureAre errors discoverable, contextual, and actionable?
OwnershipIs it clear what is borrowed, consumed, retained, or shared?
CompositionDoes the API cooperate with standard traits and other libraries?
ProgressionIs the common case short while advanced control remains reachable?
EvolutionCan the API grow without breaking or confusing existing consumers?
CostWhat complexity, compile time, allocation, or type machinery pays for the ergonomics?

No design maximizes every lens. A fluent builder may improve legibility while deferring an error. A macro may remove boilerplate while hiding the generated contract. Typestate may prevent misuse while multiplying public types. The tradeoff is part of the specimen.

The specimen format

Short atlas entries follow a fixed shape:

  1. Consumer goal — the task in domain language.
  2. Complete program — no missing setup hidden behind comments.
  3. Observed behavior — captured stdout, stderr, or failure behavior.
  4. Compile-time guarantees — what the types reject or preserve.
  5. Runtime boundary — parsing, I/O, validation, or policy that remains dynamic.
  6. Tradeoff — what the convenience costs or obscures.
  7. Question for a deep dive — the implementation mechanism worth tracing.

The atlas is comparative. A crate receives its own specimen only when it adds a substantially new primary lesson. Closely related APIs appear as contrasts under the strongest representative.

What counts as observed output?

Output blocks are captured from the checked-in programs unless marked “simplified.” The current baseline is:

rustc 1.91.0 (f8297e351 2025-10-28)

Dependency versions are locked in Cargo.lock. Formatting produced by a crate is version-sensitive, particularly diagnostics, generated help, and tracing output. A future update should rerun the example before changing its pinned version.

Network examples are different. Remote services are inherently nondeterministic, so their output records the meaningful decoded fields rather than headers, timestamps, or connection details. A production edition of this book should replace public test services with a local fixture server.

Success alone is weak evidence

An API’s design often becomes clearest at its boundary. Strong case studies therefore add at least one stress case:

  • an invalid call that fails to compile;
  • invalid external input that returns a structured error;
  • an escape hatch that exposes lower-level control;
  • a changed requirement that makes the original representation strain;
  • a comparison with another API solving the same problem differently.

Compiler diagnostics are excerpts, not stable UI. The durable claim is the property being enforced—for example, “a Bytes slice keeps its shared storage alive”—not the compiler’s exact wording.

How to spelunk without drowning

Begin at the consumer expression and move inward only when a public behavior needs explanation:

consumer goal
    ↓
complete call site
    ↓
public signature and type
    ↓
one implementation mechanism
    ↓
observable consequence and tradeoff

Stop when the next layer teaches a different subject. In Reqwest, header defaults and deferred builder errors explain the public API. Hyper’s HTTP/2 state machine does not—until the study’s question becomes protocol machinery.

How libraries are selected

GitHub stars favor applications people install and projects people admire. This guide instead prioritizes libraries that Rust programs compile against. Selection uses several imperfect signals together:

  • direct and reverse-dependency reach;
  • downloads and production longevity;
  • documentation and source accessibility;
  • ecosystem interoperability;
  • a call site with a distinct design lesson;
  • enough tradeoff to support analysis rather than praise.

Highly downloaded transitive crates are not automatically good teaching subjects. Conversely, a smaller library may be an excellent specimen if it expresses a difficult ownership or validity contract unusually well.