|
1 | 1 | cdd-rust: OpenAPI ↔ Rust |
2 | 2 | ======================== |
3 | | -[](https://www.rust-lang.org) |
4 | | -[](LICENSE-APACHE) |
5 | | -[](https://github.com/offscale/cdd-rust/actions/workflows/ci-cargo.yml) |
| 3 | +[](https://www.rust-lang.org) |
| 4 | +[](LICENSE-APACHE) |
| 5 | +[](https://github.com/offscale/cdd-rust/actions/workflows/ci-cargo.yml) |
6 | 6 |
|
7 | | -**Compiler Driven Development (CDD)** for Rust. |
| 7 | +**cdd-rust** is a compiler-driven development toolchain designed to enable "Surgical" Compiler-Driven Development. |
8 | 8 |
|
9 | | -**cdd-rust** creates a symbiotic link between your **Database**, **Rust Code**, and **OpenAPI Specifications**. Unlike traditional generators that overwrite files or hide code in "generated" directories, `cdd-rust` uses advanced AST parsing (`ra_ap_syntax`) to surgically patch your *existing* source files, strictly typed handlers, and integration tests. |
| 9 | +Unlike traditional generators that blindly overwrite files or dump code into "generated" folders, `cdd-rust` understands |
| 10 | +the Abstract Syntax Tree (AST) of your Rust code. It uses `ra_ap_syntax` (the underlying parser of **rust-analyzer**) to |
| 11 | +read, understand, and safely patch your existing source code to match your OpenAPI specifications (and vice-versa). |
10 | 12 |
|
11 | | -Uniquely, `cdd-rust` is built on a **strategy-based architecture**. While the default implementation provides a robust **Actix Web + Diesel** workflow, the core logic is decoupled into strategies and mappers, making it extensible to other ecosystems (e.g., Axum, SQLx) in the future. |
| 13 | +## ⚡️ Key Capabilities |
12 | 14 |
|
13 | | -It supports two distinct workflows: |
14 | | -1. **Scaffold | Patch (OpenAPI ➔ Rust):** Generate/update handlers, routes, and models via `BackendStrategy`. |
15 | | -2. **Reflect & Sync (Rust ➔ OpenAPI):** Generate OpenAPI specifications from your source code and DB via `ModelMapper`. |
| 15 | +### 1. Surgical Merging (OpenAPI ➔ Existing Rust) |
| 16 | + |
| 17 | +The core engine features a non-destructive patcher (`cdd-core/patcher`) capable of merging OpenAPI definitions into an |
| 18 | +existing codebase. |
| 19 | + |
| 20 | +* **AST-Aware:** It preserves your comments, whitespace, and manual formatting. |
| 21 | +* **Smart Routing:** It can parse your existing `actix_web` configuration functions and inject missing `.service()` |
| 22 | + calls without duplicating existing ones. |
| 23 | +* **Type Safety:** OpenAPI types are strictly mapped to Rust constraints: |
| 24 | + * `format: uuid` ➔ `uuid::Uuid` |
| 25 | + * `format: date-time` ➔ `chrono::DateTime<Utc>` |
| 26 | + * `format: password` ➔ `Secret<String>` |
| 27 | + |
| 28 | +### 2. Synchronization (Database ➔ Rust ➔ OpenAPI) |
| 29 | + |
| 30 | +Keep your code as the single source of truth. The `sync` workflow ensures your Rust models match your Postgres database |
| 31 | +and are ready for OpenAPI generation. |
| 32 | + |
| 33 | +* **DB Inspection:** Uses `dsync` to generate strictly typed Diesel structs from the DB schema. |
| 34 | +* **Attribute Injection:** Automatically parses generated structs to inject |
| 35 | + `#[derive(ToSchema, Serialize, Deserialize)]` and necessary imports, ensuring compatibility |
| 36 | + with [utoipa](https://github.com/juhaku/utoipa). |
| 37 | + |
| 38 | +### 3. Contract Verification (OpenAPI ➔ Tests) |
| 39 | + |
| 40 | +Generate strictly typed integration tests (`tests/api_contracts.rs`) that treat your application as a black box to |
| 41 | +verify compliance with the spec. |
| 42 | + |
| 43 | +* **Smart Mocking:** Automatically creates dummy values for Path, Query, and Body parameters based on strict type |
| 44 | + definitions. |
| 45 | +* **Runtime Expression Resolution:** fully supports OAS 3.2 runtime expressions (e.g., `{$request.body#/id}`) for |
| 46 | + HATEOAS link validation. |
| 47 | +* **Schema Validation:** Verifies that API responses strictly match the JSON Schema defined in your OpenAPI document |
| 48 | + using `jsonschema`. |
16 | 49 |
|
17 | 50 | ## ⚡️ The CDD Loop |
18 | 51 |
|
@@ -66,7 +99,8 @@ graph TD |
66 | 99 |
|
67 | 100 | ## 🏗 Architecture |
68 | 101 |
|
69 | | -The internal architecture separates the core AST/OpenAPI parsing logic from the target code generation. This allows the tool to support multiple web frameworks and ORMs through the `BackendStrategy` and `ModelMapper` traits. |
| 102 | +The internal architecture separates the core AST/OpenAPI parsing logic from the target code generation. This allows the |
| 103 | +tool to support multiple web frameworks and ORMs through the `BackendStrategy` and `ModelMapper` traits. |
70 | 104 |
|
71 | 105 | ```mermaid |
72 | 106 | graph LR |
@@ -126,82 +160,97 @@ graph LR |
126 | 160 | class T_Future future |
127 | 161 | ``` |
128 | 162 |
|
129 | | ---- |
| 163 | +The project is workspace-based to separate core logic from the command-line interface. |
130 | 164 |
|
131 | | -## 🚀 Features |
132 | | - |
133 | | -### 1. Framework-Agnostic Scaffolding (OpenAPI ➔ Rust) |
134 | | -Stop manually writing repetitive handler signatures. `cdd-rust` reads your spec and generates strictly typed code based on the active `BackendStrategy`. |
135 | | -* **Handler Scaffolding:** Transforms OpenAPI paths into `async fn` signatures with correct extractors (currently `ActixStrategy` defaults): |
136 | | - * Path variables ➔ `web::Path<Uuid>` |
137 | | - * Query strings ➔ `web::Query<Value>` |
138 | | - * Request bodies ➔ `web::Json<T>` |
139 | | -* **Route Registration:** Surgically injects route configuration strings (e.g., `cfg.service(...)`) using AST analysis, preserving existing logic. |
140 | | -* **Non-Destructive Patching:** Uses [`ra_ap_syntax`](https://docs.rs/ra_ap_syntax/) (official [rust-analyzer](https://github.com/rust-lang/rust-analyzer) parser) to edit files safely. |
141 | | - |
142 | | -### 2. Source-of-Truth Reflection (Rust ➔ OpenAPI) |
143 | | -Keep your documentation alive. Your Rust code *is* the spec. |
144 | | -* **Model Mapper Trait:** Extracts DB Schemas via `ModelMapper` (currently `DieselMapper` wrapping `dsync`) to generate/update Rust structs. |
145 | | -* **Attribute Injection:** Automatically parses structs and injects `#[derive(ToSchema)]` and `#[serde(...)]` attributes to make models OpenAPI-compatible. |
146 | | -* **Type Mapping:** Maps Rust types (`Uuid`, `chrono::NaiveDateTime`, `Decimal`) back to OpenAPI formats automatically using the `TypeMapper` module. |
147 | | - |
148 | | -### 3. Contract Safety (`test-gen`) |
149 | | -Ensure your implementation actually matches the spec using the same strategies used for code generation. |
150 | | -* **Test Generation:** Generates `tests/api_contracts.rs` based on your `openapi.yaml`. |
151 | | -* **Smart Mocking:** Automatically fills request parameters with valid dummy data based on type signatures. |
152 | | -* **Validation:** Verifies that API responses align with the JSON Schema defined in your spec. |
| 165 | +| Crate | Purpose | |
| 166 | +|----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 167 | +| **`cdd-core`** | **The Engine.** Contains the `ra_ap_syntax` parsers, the OpenAPI 3.x parser (with 3.2 shims), AST diffing logic, and the Backend Strategy traits (currently implementing `ActixStrategy`). | |
| 168 | +| **`cdd-cli`** | **The Interface.** Provides the `sync` and `test-gen` commands. | |
| 169 | +| **`cdd-web`** | **The Reference.** An Actix+Diesel implementation demonstrating the generated code and tests in action. | |
153 | 170 |
|
154 | | ---- |
| 171 | +## 📦 CLI Usage |
155 | 172 |
|
156 | | -## 📦 Command Usage |
| 173 | +### 1. Sync Pipeline (DB ➔ Models) |
157 | 174 |
|
158 | | -### 1. The Sync Pipeline |
159 | | -**DB ➔ Rust Models ➔ OpenAPI Attributes** |
160 | | -Synchronizes your database schema to your Rust structs using the configured `ModelMapper`. |
| 175 | +Synchronize Diesel models and inject OpenAPI attributes. |
161 | 176 |
|
162 | 177 | ```bash |
163 | | -cargo run -p cdd-cli -- sync \ |
164 | | - --schema-path web/src/schema.rs \ |
| 178 | +cargo run -p cdd-cli -- sync \ |
| 179 | + --schema-path web/src/schema.rs \ |
165 | 180 | --model-dir web/src/models |
166 | 181 | ``` |
167 | 182 |
|
168 | | -### 2. The Test Pipeline |
169 | | -**OpenAPI ➔ Integration Tests** |
170 | | -Generates a test suite via `BackendStrategy` (default: Actix) that treats your app as a black box. |
| 183 | +This performs the following: |
| 184 | + |
| 185 | +1. Reads `schema.rs`. |
| 186 | +2. Generates rust structs in `models/` using `diesel/dsync` logic. |
| 187 | +3. **Patches** the files to add `#![allow(missing_docs)]`, `use utoipa::ToSchema;`, and derive macros. |
| 188 | + |
| 189 | +### 2. Test Generation (OpenAPI ➔ Tests) |
| 190 | + |
| 191 | +Scaffold integration tests to verify your implementation meets the contract. |
171 | 192 |
|
172 | 193 | ```bash |
173 | | -cargo run -p cdd-cli -- test-gen \ |
174 | | - --openapi-path docs/openapi.yaml \ |
175 | | - --output-path web/tests/api_contracts.rs \ |
| 194 | +cargo run -p cdd-cli -- test-gen \ |
| 195 | + --openapi-path docs/openapi.yaml \ |
| 196 | + --output-path web/tests/api_contracts.rs \ |
176 | 197 | --app-factory crate::create_app |
177 | 198 | ``` |
178 | 199 |
|
179 | | ---- |
| 200 | +This generates a test file that: |
| 201 | + |
| 202 | +1. Initializes your App factory. |
| 203 | +2. Iterates through every route in your OpenAPI spec. |
| 204 | +3. Sensibly mocks requests. |
| 205 | +4. Validates that your Rust implementation returns the headers and bodies defined in the YAML. |
180 | 206 |
|
181 | | -## 🛠 Project Structure |
| 207 | +## 🛠 OpenAPI Compliance |
182 | 208 |
|
183 | | -* **`core/`**: The engine. Contains AST parsers, strategies, and the diff/patch logic. |
184 | | - * `strategies.rs`: Defines `BackendStrategy` trait and `ActixStrategy`. |
185 | | - * `patcher.rs`: Surgical code editing. |
186 | | - * `oas.rs`: Parses OpenAPI YAML into Intermediate Representations. |
187 | | - * `handlers/routes/contract_test`: Functional modules utilizing strategies to generate code. |
188 | | -* **`cli/`**: The workflow runner. Wires up specific strategies to commands. |
189 | | - * `generator.rs`: Defines `ModelMapper` and `DieselMapper`. |
190 | | - * `main.rs`: Dependency injection root. |
191 | | -* **`web/`**: Reference implementation. An Actix Web + Diesel project demonstrating the generated code in action. |
| 209 | +`cdd-rust` features a highly compliant custom parser found in `core/src/oas`. |
192 | 210 |
|
193 | | -## 🎨 Design Principles |
| 211 | +* **Versions:** Supports OpenAPI 3.0 and 3.1 directly. |
| 212 | +* **Compatibility:** Implements shims for **OpenAPI 3.2**, specifically handling the `$self` keyword for Base URI |
| 213 | + determination (Appendix F) and downgrading version strings for library compatibility. |
| 214 | +* **Resolution:** Full support for local, relative, and remote `$ref` resolution. |
| 215 | +* **Polymorphism:** handles `oneOf`, `anyOf`, and `allOf` (flattening) into Rust Enums and Structs. |
| 216 | +* **Extractors:** Maps OAS parameters to backend-specific extractors (e.g., `web::Query`, `web::Path`, `web::Json`, |
| 217 | + `SecurityScheme`). |
| 218 | + |
| 219 | +## Developer Guide |
| 220 | + |
| 221 | +### Prerequisites |
| 222 | + |
| 223 | +* Rust (Nightly toolchain required for `ra_ap_syntax` compatibility feature flags in some contexts). |
| 224 | +* PostgreSQL (if running the reference web implementation). |
| 225 | + |
| 226 | +### Installation |
| 227 | + |
| 228 | +```bash |
| 229 | +git clone https://github.com/offscale/cdd-rust |
| 230 | +cd cdd-rust |
| 231 | +cargo build |
| 232 | +``` |
| 233 | + |
| 234 | +### Running Tests |
| 235 | + |
| 236 | +```bash |
| 237 | +# Run unit tests |
| 238 | +cargo test |
| 239 | + |
| 240 | +# Run the generated contract tests (requires web/tests/api_contracts.rs to be generated) |
| 241 | +cargo test -p cdd-web |
| 242 | +``` |
| 243 | + |
| 244 | +## License |
194 | 245 |
|
195 | | -* **No Magic Folders:** We generate code you can read, debug, and commit. |
196 | | -* **Lossless Patching:** We edit your source files without breaking your style. |
197 | | -* **Pluggable Backend:** Core logic is decoupled from specific frameworks (Actix, Axum, etc.). |
198 | | -* **Type Safety:** `Uuid`, `chrono`, and `rust_decimal` are first-class citizens. |
| 246 | +Licensed under either of Apache License, Version 2.0 or MIT license at your option. |
199 | 247 |
|
200 | 248 | --- |
201 | 249 |
|
202 | 250 | ## Developer guide |
203 | 251 |
|
204 | | -Install the latest version of [Rust](https://www.rust-lang.org). We tend to use nightly versions. [CLI tool for installing Rust](https://rustup.rs). |
| 252 | +Install the latest version of [Rust](https://www.rust-lang.org). We tend to use nightly |
| 253 | +versions. [CLI tool for installing Rust](https://rustup.rs). |
205 | 254 |
|
206 | 255 | We use [rust-clippy](https://github.com/rust-lang-nursery/rust-clippy) linters to improve code quality. |
207 | 256 |
|
|
0 commit comments