RepoPilot

How do their APIs compare?

About astral-sh/ruff · 2 messages · last activity 9/9/2026

Question

How do their APIs compare?

RepoPilot

I should clarify: ruff and utoipa aren't really comparable on "API" in the same sense, since they serve entirely different purposes and are consumed in different ways. Let me lay out what the retrieved data actually shows for each, rather than force a feature-by-feature comparison.

astral-sh/ruff — CLI/tool surface, not a library API

Ruff is primarily consumed as a command-line tool (linter + formatter), not as a Rust library API for downstream consumers. The retrieved chunks reflect this:

  • It's structured as a workspace of internal crates (ruff_linter, ruff_formatter, ruff_annotate_snippets, ruff_db, etc.), per the import graph in the RepoPilot analysis, with entry points like [crates/ruff_linter/src/checkers/ast/analyze/mod.rs] and [crates/ruff_formatter/src/printer/mod.rs] being the most-depended-on internal modules.
  • Diagnostics generation from source (e.g., stdin) is exposed internally via functions like the one documented at [crates/ruff/src/diagnostics.rs:L382].
  • There isn't a public "API" for embedding Ruff into other Rust programs in the way utoipa is embedded — its primary interface is the CLI (pyproject.toml config, rule codes, --fix, etc.), per the README's feature list [README.md:L68-L102 region / overview].

So "API" for ruff really means: CLI flags, configuration schema (pyproject.toml/ruff.toml), and the rule/diagnostic model — not a stable Rust crate API for third parties.

juhaku/utoipa — a Rust proc-macro/builder API for OpenAPI generation

Utoipa's API is explicitly designed for library consumption, centered on:

  • Derive/attribute macros like #[utoipa::path(...)] and #[derive(OpenApi)], which developers annotate directly on handler functions to generate OpenAPI docs, as shown in the actix-web and axum examples [utoipa-gen/src/lib.rs:L1517-L1556] and [utoipa-axum/src/lib.rs:L221-L260].
  • Builder-style runtime types, e.g., OpenApiBuilder, and direct mutation of the generated OpenApi struct at runtime (doc.info.title = ...), as documented in [utoipa-gen/README.md:L277-L302] and mirrored in [README.md:L277-L302].
  • Router integration APIs for frameworks — e.g., OpenApiRouter::nest, which wraps axum::Router::nest while also merging OpenAPI path metadata, seen in [utoipa-axum/src/router.rs:L289-L328].
  • A Modify trait for runtime OpenAPI post-processing, referenced in the README modify-at-runtime section.
  • Internally, its proc-macro crate (utoipa-gen) implements custom Parse impls to read macro attribute syntax, e.g., DeriveToResponseValue::parse for response attributes [utoipa-gen/src/path/response.rs:L536-L578] and route-method parsing for actix [utoipa-gen/src/ext/actix.rs:L164-L221].

Summary of the contrast

  • ruff: an application whose "API" is its CLI + config surface; internal crates are implementation details not meant for external API stability.
  • utoipa: a library whose entire value proposition is its API — proc-macro attributes for annotating code, builder types for runtime OpenAPI manipulation, and framework-specific integration crates (utoipa-axum, actix extras) that extend routing APIs.

If you want, I can dig deeper into either side — e.g., ruff's rule/diagnostic data structures, or utoipa's Modify trait and builder pattern internals.

FOLLOW_UPS:

  • How does utoipa's Modify trait work internally?
  • What does ruff's diagnostic data structure look like?
  • How does utoipa-axum integrate OpenAPI with routing?

Want to ask your own question?

Open chat for astral-sh/ruff

Public Q&A. Generated by RepoPilot from the actual source of astral-sh/ruff. AI answers can be incomplete or stale — verify before relying on them.