Skip to content

Commit 1ae4c75

Browse files
committed
!
1 parent 7f0fb40 commit 1ae4c75

12 files changed

Lines changed: 382 additions & 69 deletions

File tree

.github/copilot-instructions.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# RustAPI - Copilot Instructions
2+
3+
## Project Context
4+
RustAPI is a FastAPI-like web framework for Rust. The core philosophy is **"DX-First"**: endpoint = 1 function + 1 attribute macro.
5+
6+
**Status:** Phase 1 MVP Complete | Phase 2 (Validation + OpenAPI) In Progress
7+
8+
## Architecture
9+
10+
**Workspace structure:**
11+
- `rustapi-rs/` - Public facade crate (users depend on this)
12+
- `rustapi-core/` - Core implementation (router, extractors, handlers, server)
13+
- `rustapi-macros/` - Procedural macros (planned `#[get]`, `#[post]`)
14+
- `examples/hello-world/` - Reference implementation
15+
16+
**Key design rule:** All dependencies are wrapped - never expose `hyper`, `matchit`, etc. directly.
17+
18+
## Code Patterns
19+
20+
### Always use prelude import
21+
```rust
22+
use rustapi_rs::prelude::*;
23+
```
24+
25+
### Handler signature pattern
26+
Handlers are async functions with up to 5 extractor arguments:
27+
```rust
28+
async fn get_user(Path(id): Path<u32>, State(db): State<Database>) -> Json<User> {
29+
// Business logic only - no framework ceremony
30+
}
31+
```
32+
33+
### Route registration
34+
Use `{param}` syntax for path parameters (converted to `:param` internally):
35+
```rust
36+
RustApi::new()
37+
.route("/users/{id}", get(get_user))
38+
.route("/users", post(create_user))
39+
```
40+
41+
### Response helpers
42+
- `Json(data)` → 200 OK with JSON
43+
- `created(data)` → 201 Created
44+
- `no_content()` → 204 No Content
45+
- `ApiError::not_found("msg")` → 404 JSON error
46+
47+
## Key Traits
48+
49+
| Trait | Purpose |
50+
|-------|---------|
51+
| `Handler<T>` | 0-5 arg async functions → endpoint handlers |
52+
| `FromRequestParts` | Extractors that don't consume body (Path, Query, State) |
53+
| `FromRequest` | Extractors that consume body (Json, Body) |
54+
| `IntoResponse` | Types convertible to HTTP response |
55+
56+
## Commands
57+
58+
```powershell
59+
cargo build # Build workspace
60+
cargo run -p hello-world # Run example server (http://127.0.0.1:8080)
61+
cargo test --workspace # Run all tests
62+
cargo clippy --workspace # Lint
63+
```
64+
65+
## File Reference
66+
67+
| To understand... | Read |
68+
|------------------|------|
69+
| Usage example | `examples/hello-world/src/main.rs` |
70+
| App builder | `crates/rustapi-core/src/app.rs` |
71+
| Extractors | `crates/rustapi-core/src/extract.rs` |
72+
| Handler trait | `crates/rustapi-core/src/handler.rs` |
73+
| Error format | `crates/rustapi-core/src/error.rs` |
74+
| Full context | `AGENTS.md`, `memories/rustapi_memory_bank.md` |

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
/memories

AGENTS.md

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
# AGENTS.md - RustAPI AI Agent Guide
2+
3+
> This file helps AI coding agents understand the RustAPI codebase quickly.
4+
5+
## Project Overview
6+
7+
**RustAPI** is a FastAPI-like web framework for Rust that combines Rust's performance and memory safety with FastAPI's developer experience.
8+
9+
**Core Philosophy:** "DX-First" - endpoint = 1 function + 1 attribute macro
10+
11+
**Goals:**
12+
- Make Rust API development feel as easy as FastAPI
13+
- Eliminate boilerplate: handler function + attribute macro = endpoint
14+
- Automatic OpenAPI documentation (planned)
15+
- Type-safe compile-time validation
16+
17+
**Status:** Phase 1 MVP Complete ✅ | Phase 2 (Validation + OpenAPI) In Progress 🔄
18+
19+
---
20+
21+
## Crate Structure
22+
23+
```
24+
rustapi/
25+
├── rustapi-rs/ # Public facade - published to crates.io
26+
├── rustapi-core/ # Core implementation
27+
├── rustapi-macros/ # Procedural macros
28+
└── examples/
29+
└── hello-world/ # Example application
30+
```
31+
32+
| Crate | Purpose |
33+
|-------|---------|
34+
| `rustapi-rs` | **Public facade** - the crate users depend on, re-exports core + macros |
35+
| `rustapi-core` | **Core implementation** - router, extractors, handlers, server, errors |
36+
| `rustapi-macros` | **Procedural macros** - `#[get]`, `#[post]`, etc. (planned) |
37+
38+
---
39+
40+
## Key Modules (rustapi-core)
41+
42+
| Module | Responsibility |
43+
|--------|----------------|
44+
| `app.rs` | `RustApi` builder - main entry point with `new()`, `route()`, `get()`, `post()`, `state()`, `run()` |
45+
| `router.rs` | Radix tree router using `matchit`, method-based routing (GET, POST, PUT, DELETE, PATCH) |
46+
| `handler.rs` | `Handler` trait with implementations for 0-5 argument handlers |
47+
| `extract.rs` | Extractors: `Json<T>`, `Path<T>`, `Query<T>`, `State<T>`, `Body` |
48+
| `response.rs` | `IntoResponse` trait, helpers: `json()`, `created()`, `no_content()`, `text()` |
49+
| `error.rs` | `ApiError` struct, `Result<T>` type alias, JSON error format |
50+
| `server.rs` | Hyper 1.x server with graceful shutdown (Ctrl+C) |
51+
52+
---
53+
54+
## Coding Conventions
55+
56+
### Import Pattern
57+
```rust
58+
use rustapi_rs::prelude::*;
59+
```
60+
61+
### Handler Signatures
62+
Handlers should be readable like documentation:
63+
```rust
64+
async fn get_user(Path(id): Path<u32>, State(db): State<Database>) -> Json<User> {
65+
// Business logic only
66+
}
67+
```
68+
69+
### Extractor Patterns
70+
| Extractor | Usage | Route Example |
71+
|-----------|-------|---------------|
72+
| `Path<T>` | URL path parameters | `/users/{id}` |
73+
| `Query<T>` | Query string params | `?page=1&limit=10` |
74+
| `Json<T>` | JSON request body | POST/PUT requests |
75+
| `State<T>` | Shared application state | Database connections |
76+
| `Body` | Raw request body | File uploads |
77+
78+
### Response Patterns
79+
```rust
80+
Json(data) // 200 OK with JSON
81+
created(data) // 201 Created with JSON
82+
no_content() // 204 No Content
83+
text("hello") // 200 OK with plain text
84+
ApiError::not_found("User not found") // 404 JSON error
85+
```
86+
87+
### Path Parameter Syntax
88+
- Use `{param}` format in routes (converted to `:param` internally)
89+
- Example: `.get("/users/{id}", get_user)` extracts `id` parameter
90+
91+
### Wrapper Philosophy
92+
**All dependencies are wrapped** - never exposed directly in public API:
93+
- `matchit` → Router abstraction
94+
- `hyper` → Server abstraction
95+
- `validator` (planned) → Validation abstraction
96+
- `utoipa` (planned) → Schema abstraction
97+
98+
---
99+
100+
## Standard JSON Error Format
101+
102+
```json
103+
{
104+
"error": {
105+
"type": "validation_error",
106+
"message": "Request validation failed",
107+
"fields": [
108+
{"field": "email", "code": "email", "message": "Invalid email format"}
109+
]
110+
}
111+
}
112+
```
113+
114+
---
115+
116+
## Build & Test Commands
117+
118+
```powershell
119+
# Build the workspace
120+
cargo build
121+
122+
# Run the hello-world example
123+
cargo run -p hello-world
124+
125+
# Run all tests
126+
cargo test --workspace
127+
128+
# Check for errors without building
129+
cargo check --workspace
130+
131+
# Format code
132+
cargo fmt --all
133+
134+
# Lint
135+
cargo clippy --workspace
136+
```
137+
138+
### Testing Endpoints (PowerShell)
139+
```powershell
140+
Invoke-RestMethod -Uri http://127.0.0.1:8080/
141+
Invoke-RestMethod -Uri http://127.0.0.1:8080/health
142+
Invoke-RestMethod -Uri http://127.0.0.1:8080/users/42
143+
```
144+
145+
---
146+
147+
## Handler Trait System
148+
149+
```rust
150+
pub trait Handler<T>: Clone + Send + Sync + 'static {
151+
fn call(self, req: Request) -> impl Future<Output = Response> + Send;
152+
}
153+
```
154+
155+
- Implemented for function pointers with **0-5 arguments**
156+
- Each argument must implement `FromRequest` or `FromRequestParts`
157+
- `FromRequestParts` - extractors that don't consume body (Path, Query, State)
158+
- `FromRequest` - extractors that consume body (Json, Body)
159+
160+
---
161+
162+
## Development Phases
163+
164+
### ✅ Phase 1 - MVP (Complete)
165+
- Workspace structure with 3 crates
166+
- Hyper 1.x server with graceful shutdown
167+
- Radix tree router (matchit)
168+
- Handler trait (0-5 args)
169+
- All core extractors: Json, Path, Query, State, Body
170+
- IntoResponse + response helpers
171+
- ApiError + Result type
172+
- Tracing integration
173+
174+
### 🔄 Phase 2 - Validation + OpenAPI (Current)
175+
- `rustapi-validate` crate - wrapper for `validator`
176+
- `#[derive(Validate)]` macro
177+
- Validation rules: email, length, range, regex, non_empty
178+
- 422 JSON error format
179+
- `rustapi-openapi` crate - wrapper for `utoipa`
180+
- `/openapi.json` endpoint
181+
- Swagger UI at `/docs`
182+
183+
### 📋 Phase 3-4 - Extras (Planned)
184+
- Tower middleware integration
185+
- JWT, CORS, rate limiting (`rustapi-extras`)
186+
- Additional extractors: Headers, Cookies, IpAddr
187+
- TestClient helper
188+
- Benchmark suite
189+
190+
---
191+
192+
## Key Files to Read
193+
194+
| Purpose | File |
195+
|---------|------|
196+
| Example usage | `examples/hello-world/src/main.rs` |
197+
| Core exports | `crates/rustapi-core/src/lib.rs` |
198+
| App builder | `crates/rustapi-core/src/app.rs` |
199+
| Router impl | `crates/rustapi-core/src/router.rs` |
200+
| Extractors | `crates/rustapi-core/src/extract.rs` |
201+
| Error handling | `crates/rustapi-core/src/error.rs` |
202+
| Project context | `memories/rustapi_memory_bank.md` |
203+
| Task list | `memories/TASKLIST.md` |
204+
205+
---
206+
207+
## Quick Reference
208+
209+
```rust
210+
use rustapi_rs::prelude::*;
211+
212+
#[tokio::main]
213+
async fn main() {
214+
RustApi::new()
215+
.get("/", index)
216+
.get("/users/{id}", get_user)
217+
.post("/users", create_user)
218+
.state(AppState::new())
219+
.run("127.0.0.1:8080")
220+
.await;
221+
}
222+
223+
async fn index() -> &'static str {
224+
"Hello, RustAPI!"
225+
}
226+
227+
async fn get_user(Path(id): Path<u32>) -> Json<User> {
228+
Json(User { id, name: "Alice".into() })
229+
}
230+
231+
async fn create_user(Json(payload): Json<CreateUser>) -> impl IntoResponse {
232+
created(User { id: 1, name: payload.name })
233+
}
234+
```
235+
236+
---
237+
238+
## MSRV & License
239+
240+
- **Minimum Supported Rust Version:** 1.75+
241+
- **License:** MIT OR Apache-2.0

Cargo.lock

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"crates/rustapi-rs",
55
"crates/rustapi-core",
66
"crates/rustapi-macros",
7+
"examples/hello-world",
78
]
89

910
[workspace.package]

0 commit comments

Comments
 (0)