Skip to content

Commit a544ccf

Browse files
committed
docs: golden path as canonical start (handler → OpenAPI → probes)
Wire README, docs hub, cookbook, and examples around docs/GOLDEN_PATH.md. golden_path example uses route macros so /docs/openapi.json lists /api/v1/ping. clippy: multipart parse_multipart_part use ? for optional header boundary.
1 parent cc9f80f commit a544ccf

13 files changed

Lines changed: 307 additions & 90 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ answer.md
3636
!docs/native_openapi.md
3737
!docs/PRODUCTION_BASELINE.md
3838
!docs/PRODUCTION_CHECKLIST.md
39+
!docs/GOLDEN_PATH.md
3940
!docs/cookbook/src/**/*.md
4041
tasks.md
4142
/mcps

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12-
- **`golden_path` example** (`crates/rustapi-rs/examples/golden_path.rs`) — minimal production-shaped service with `production_defaults`, health probes, and graceful shutdown.
12+
- **`docs/GOLDEN_PATH.md`** — canonical handler → OpenAPI → probes → MCP/deploy walkthrough; linked from README, docs hub, cookbook SUMMARY, Getting Started.
13+
- **`golden_path` example** uses route macros + tags so `/docs/openapi.json` includes `/api/v1/ping` (not only `.route()` wiring).
1314

1415
### Changed
1516

1617
- **Production Readiness v0.2** ([#200](https://github.com/Tuntii/RustAPI/issues/200)): coverage CI publishes HTML + Cobertura artifacts with job summary; release-drafter publishes drafts on `v*` tags; README links [Production Checklist](docs/PRODUCTION_CHECKLIST.md) in the header.
18+
- README Quick Start: golden path first; document OpenAPI at `/docs/openapi.json`; prefer macros for OpenAPI registration; `tracing-subscriber` + `production_defaults` in the hello snippet.
1719
- Dependency updates: `actions/checkout@v7`, `actions/cache@v6`, `brotli` 8, `rcgen` 0.14, `tera` 2, `thiserror` 2, OpenTelemetry 0.32 stack, `sqlx` 0.9, `tracing-opentelemetry` 0.33.
1820
- Default `rustapi-rs` dependency tree slimmed from ~259 to ~158 transitive crates by removing always-on `tracing-subscriber` and gating `rust-i18n` behind the `i18n` feature (English fallbacks by default).
1921
- `RustApi::new()` no longer auto-initializes `tracing-subscriber`; initialize tracing in `main` (CLI templates already do).

README.md

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<br />
1010

1111
<a href="https://rustapi.cloud"><strong>Website</strong></a> ·
12+
<a href="docs/GOLDEN_PATH.md"><strong>Golden Path</strong></a> ·
1213
<a href="docs/cookbook/src/SUMMARY.md"><strong>Cookbook</strong></a> ·
1314
<a href="docs/PRODUCTION_CHECKLIST.md"><strong>Production Checklist</strong></a> ·
1415
<a href="docs/cookbook/src/recipes/rustapi_cloud.md"><strong>Deploy to Cloud</strong></a> ·
@@ -38,6 +39,22 @@
3839

3940
---
4041

42+
## Golden Path (start here)
43+
44+
**Handler → OpenAPI (`/docs`) → production probes → (optional) MCP / deploy.**
45+
46+
```bash
47+
cargo run -p rustapi-rs --example golden_path
48+
# curl http://127.0.0.1:8080/api/v1/ping
49+
# open http://127.0.0.1:8080/docs
50+
```
51+
52+
Full walkthrough: **[docs/GOLDEN_PATH.md](docs/GOLDEN_PATH.md)** · example: [`golden_path.rs`](crates/rustapi-rs/examples/golden_path.rs)
53+
54+
Everything else (JWT, jobs, WS, full extras) branches off this path.
55+
56+
---
57+
4158
## Overview
4259

4360
RustAPI is a Rust web framework built on **hyper 1.x** and **tokio**, designed for minimal boilerplate while retaining full control over performance. It uses a **facade architecture** (`rustapi-rs`) that shields user code from internal crate changes, keeping the public API stable as internals evolve.
@@ -190,11 +207,15 @@ Current benchmark methodology and canonical published performance claims live in
190207

191208
## Quick Start
192209

193-
**Recommended usage** (short and clean macro paths):
210+
Prefer the **[Golden Path](docs/GOLDEN_PATH.md)** for the recommended service shape (`production_defaults` + probes + OpenAPI). Minimal hello:
211+
212+
**Recommended usage** (short macro paths via crate alias):
194213

195214
```toml
196215
[dependencies]
197216
api = { package = "rustapi-rs", version = "0.1.551" }
217+
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
218+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
198219
```
199220

200221
```rust
@@ -208,13 +229,19 @@ async fn hello(Path(name): Path<String>) -> Json<Message> {
208229
Json(Message { text: format!("Hello, {}!", name) })
209230
}
210231

211-
#[api::main]
232+
#[tokio::main]
212233
async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
213-
RustApi::auto().run("127.0.0.1:8080").await
234+
tracing_subscriber::fmt::init();
235+
RustApi::auto()
236+
.production_defaults("hello")
237+
.run("127.0.0.1:8080")
238+
.await
214239
}
215240
```
216241

217-
`RustApi::auto()` collects all macro-annotated handlers, generates OpenAPI documentation (served at `/docs`), and starts a multi-threaded tokio runtime.
242+
`RustApi::auto()` collects macro-annotated handlers, serves Swagger UI at `/docs`, OpenAPI at `/docs/openapi.json`, and starts a multi-threaded tokio runtime. Spec path is **`/docs/openapi.json`** (not `/openapi.json`).
243+
244+
Use **route macros** (`#[api::get]`) so OpenAPI includes your paths. Plain `.route(...)` alone does not register operations in the spec.
218245

219246
### MCP in 3 lines
220247

@@ -223,48 +250,11 @@ let mcp = McpServer::from_rustapi(&app, McpConfig::new().allowed_tags(["public"]
223250
run_rustapi_and_mcp_with_shutdown(app, "0.0.0.0:8080", mcp, "0.0.0.0:9090", tokio::signal::ctrl_c()).await?;
224251
```
225252

226-
Every tagged endpoint becomes an AI agent tool instantly.
253+
Tag handlers with `#[api::tag("public")]` (or `"agent"`) so only intentional routes become tools. Example: `mcp_tools`.
227254

228-
> **Tip:** Alias the crate as `api` (or `myapi`, `server`, etc.) for clean `#[api::get]` / `#[api::main]` macros — similar to FastAPI's import style.
229-
230-
For production deployments, you can enable standard probe endpoints without writing handlers manually:
231-
232-
```rust
233-
use api::prelude::*;
234-
235-
#[api::main]
236-
async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
237-
let health = HealthCheckBuilder::new(true)
238-
.add_check("database", || async { HealthStatus::healthy() })
239-
.build();
240-
241-
RustApi::auto()
242-
.with_health_check(health)
243-
.run("127.0.0.1:8080")
244-
.await
245-
}
246-
```
247-
248-
This registers:
249-
- `/health` — aggregate dependency health
250-
- `/ready` — readiness probe (`503` when dependencies are unhealthy)
251-
- `/live` — lightweight liveness probe
252-
253-
Or use a single production baseline preset:
254-
255-
```rust
256-
use api::prelude::*;
257-
258-
#[api::main]
259-
async fn main() -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
260-
RustApi::auto()
261-
.production_defaults("users-api")
262-
.run("127.0.0.1:8080")
263-
.await
264-
}
265-
```
255+
> **Tip:** Alias the crate as `api` for clean `#[api::get]` macros.
266256
267-
`production_defaults()` enables request IDs, tracing spans, and standard probe endpoints in one call.
257+
`production_defaults(name)` enables request IDs, tracing spans, and `/live` `/ready` `/health` in one call. Details: [Production Baseline](docs/PRODUCTION_BASELINE.md).
268258

269259
## Feature Flags
270260

@@ -307,6 +297,7 @@ See [CHANGELOG.md](CHANGELOG.md) for full history. Highlights in **v0.1.551**:
307297

308298
| Resource | Link |
309299
|----------|------|
300+
| **Golden Path** | [docs/GOLDEN_PATH.md](docs/GOLDEN_PATH.md) |
310301
| Docs hub | [docs/README.md](docs/README.md) |
311302
| Cookbook | [docs/cookbook/src/SUMMARY.md](docs/cookbook/src/SUMMARY.md) |
312303
| Getting started | [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md) |
@@ -316,7 +307,7 @@ See [CHANGELOG.md](CHANGELOG.md) for full history. Highlights in **v0.1.551**:
316307
| Community & contributing | [docs/COMMUNITY.md](docs/COMMUNITY.md) |
317308
| API reference | [docs.rs/rustapi-rs](https://docs.rs/rustapi-rs) |
318309

319-
**Examples:** start with [`golden_path`](crates/rustapi-rs/examples/golden_path.rs) (`cargo run -p rustapi-rs --example golden_path`), then browse [`crates/rustapi-rs/examples/`](crates/rustapi-rs/examples/) and **[rustapi-rs-examples](https://github.com/Tuntii/rustapi-rs-examples)**.
310+
**Examples:** [`golden_path`](crates/rustapi-rs/examples/golden_path.rs) first, then [`crates/rustapi-rs/examples/`](crates/rustapi-rs/examples/) and **[rustapi-rs-examples](https://github.com/Tuntii/rustapi-rs-examples)**.
320311

321312
## Community & Contributing
322313

crates/rustapi-core/src/multipart.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,9 @@ fn trim_trailing_crlf(mut data: Vec<u8>) -> Vec<u8> {
584584
fn parse_multipart_part(part: &[u8]) -> Option<MultipartField> {
585585
let (header_end, body_start) = if let Some(pos) = find_subsequence(part, b"\r\n\r\n", 0) {
586586
(pos, pos + 4)
587-
} else if let Some(pos) = find_subsequence(part, b"\n\n", 0) {
588-
(pos, pos + 2)
589587
} else {
590-
return None;
588+
let pos = find_subsequence(part, b"\n\n", 0)?;
589+
(pos, pos + 2)
591590
};
592591

593592
let headers_section = String::from_utf8_lossy(&part[..header_end]);

crates/rustapi-rs/examples/README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
11
# RustAPI Examples
22

3-
This directory contains the in-repository examples for the `rustapi-rs` facade crate.
3+
In-repository examples for the `rustapi-rs` facade crate.
4+
5+
## Start here: `golden_path`
6+
7+
Minimal production-shaped service: macro route + `Schema`, OpenAPI/Swagger, `production_defaults` probes, graceful shutdown.
8+
9+
```sh
10+
cargo run -p rustapi-rs --example golden_path
11+
```
12+
13+
Then:
14+
15+
- `GET http://127.0.0.1:8080/api/v1/ping``{"status":"ok"}`
16+
- `GET http://127.0.0.1:8080/live` (and `/ready`, `/health`)
17+
- Browser: `http://127.0.0.1:8080/docs` · spec: `/docs/openapi.json`
18+
19+
Guide: [docs/GOLDEN_PATH.md](../../../docs/GOLDEN_PATH.md)
420

521
## Available examples
622

723
### `file_upload`
824

25+
926
Multipart file upload with `Multipart`, body limits, and safe filename handling.
1027

1128
Run it with:

crates/rustapi-rs/examples/golden_path.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
//! Golden-path production baseline — the smallest service shape we recommend.
1+
//! Golden path smallest service shape we recommend shipping.
22
//!
3-
//! Run:
3+
//! Story in one command:
4+
//! 1. handler + `Schema` → typed JSON
5+
//! 2. `RustApi::auto()` → OpenAPI + Swagger UI at `/docs`
6+
//! 3. `production_defaults` → request IDs, tracing, `/live` `/ready` `/health`
7+
//! 4. graceful shutdown on Ctrl-C
8+
//!
9+
//! Run (from repo root):
410
//! ```bash
511
//! cargo run -p rustapi-rs --example golden_path
612
//! ```
713
//!
814
//! Verify:
9-
//! - `GET http://127.0.0.1:8080/live` → 200
10-
//! - `GET http://127.0.0.1:8080/ready` → 200
11-
//! - `GET http://127.0.0.1:8080/health` → 200
12-
//! - `GET http://127.0.0.1:8080/api/v1/ping` → `{"status":"ok"}`
15+
//! ```bash
16+
//! curl -s http://127.0.0.1:8080/api/v1/ping
17+
//! curl -s http://127.0.0.1:8080/live
18+
//! curl -s http://127.0.0.1:8080/docs/openapi.json | head
19+
//! # browser: http://127.0.0.1:8080/docs
20+
//! ```
1321
//!
14-
//! See [Production Checklist](../../../docs/PRODUCTION_CHECKLIST.md) before real traffic.
22+
//! Guide: [docs/GOLDEN_PATH.md](../../../docs/GOLDEN_PATH.md)
23+
//! Before real traffic: [Production Checklist](../../../docs/PRODUCTION_CHECKLIST.md)
1524
1625
use rustapi_rs::prelude::*;
1726
use tokio::signal;
@@ -21,6 +30,10 @@ struct PingResponse {
2130
status: &'static str,
2231
}
2332

33+
/// Liveness-style app check. Probes come from `production_defaults`.
34+
#[rustapi_rs::get("/api/v1/ping")]
35+
#[rustapi_rs::tag("public")]
36+
#[rustapi_rs::summary("Ping - golden path app check")]
2437
async fn ping() -> Json<PingResponse> {
2538
Json(PingResponse { status: "ok" })
2639
}
@@ -34,7 +47,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
3447
.on_shutdown(|| async {
3548
tracing::info!("graceful shutdown complete");
3649
})
37-
.route("/api/v1/ping", get(ping))
3850
.run_with_shutdown("127.0.0.1:8080", async {
3951
signal::ctrl_c().await.ok();
4052
})

docs/GETTING_STARTED.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
> Build your first API in under 5 minutes.
44
5+
**Canonical story:** [Golden Path](GOLDEN_PATH.md) — handler → OpenAPI → `production_defaults` → optional MCP/deploy.
6+
7+
In-repo demo:
8+
9+
```bash
10+
cargo run -p rustapi-rs --example golden_path
11+
# http://127.0.0.1:8080/docs · /docs/openapi.json · GET /api/v1/ping
12+
```
13+
514
---
615

716
## Prerequisites

0 commit comments

Comments
 (0)