Skip to content

Commit 2114edc

Browse files
AuroraMasterroot
andauthored
[rust-salvo] Add Rust server generator targeting the Salvo web framework (#23772)
* Add Rust Salvo server code generator - Add RustSalvoServerCodegen.java with traditional MVC architecture - Support for Salvo web framework with async handlers - Include request validation, auth middleware, and CORS support - Generate handlers, models, routes, and middleware modules - Follow OpenAPI Generator conventions for consistency * Add comprehensive testing for Rust Salvo server generator - Register RustSalvoServerCodegen in SPI configuration - Add RustSalvoServerCodegenTest with comprehensive test cases - Create test OpenAPI specs for basic, auth, and validation scenarios - Test file generation, dependency injection, and middleware support - Verify Cargo.toml, handlers, routes, and validation features * [rust-salvo] Modernize generator for Salvo 0.93 and refresh deps Bring rust-salvo up to current Salvo idioms after the long rebase against upstream master. The generator was previously pinned to Salvo 0.73 with deprecated `<>` path syntax, a non-existent `salvo-cors` crate, a broken `lambdaVersion` lambda reference, and a base64 0.21 API that no longer compiles on the 0.22 line. Highlights: - Cargo.mustache: salvo 0.73 -> 0.93, validator 0.18 -> 0.20, drop the fake `salvo-cors` dependency (cors is a salvo feature), pin tokio to the macros/rt-multi-thread/signal subset, add base64/async-trait. - Codegen: stop converting OpenAPI `{id}` paths to the deprecated `<id>` syntax; Salvo 0.76+ matches OpenAPI directly. Push boolean option defaults into additionalProperties so templates and tests can rely on them. - handlers.mustache: rewrite to use `salvo::oapi::extract::{JsonBody, PathParam, QueryParam, HeaderParam, FormBody}` instead of mixing the oapi endpoint macro with the legacy `#[salvo(extract(...))]` attribute. Triple-stash `dataType` so generics like `Vec<String>` aren't HTML-escaped. - handlers-mod.mustache: iterate `apis` by tag (one `pub mod` per API group) instead of iterating operations, which produced duplicates. - middleware.mustache: switch base64 to the 0.22 `Engine` API and stop bubbling a `Result` out of a `()`-returning handler. - models.mustache: derive `salvo::oapi::ToSchema` so generated models can flow through `JsonBody<T>` and friends. Triple-stash `dataType`. - Add `bin/configs/manual/rust-salvo-petstore.yaml` so samples can be regenerated through the standard flow. - Tests: align fixtures with the new output (salvo 0.93, validator 0.20, modern auth struct names, per-tag handler module names). Known follow-ups: a full petstore generation still has ~21 remaining `cargo check` errors around inline-enum duplication and ToSchema coverage; those require model-template work to reach axum-level parity. * [rust-salvo] Make generated petstore code pass cargo check - models.mustache: drop the inline-enum block that emitted empty `pub enum Status {}` for each model with an enum-valued field. The variant set was never populated (the codegen still types these as `Option<String>`), so the empty enums only produced E0428 duplicate definitions across models that happened to share a field name. - models.mustache: `use crate::models;` so `models::Foo` cross-references emitted by the codegen resolve while we are already inside the models module (same trick rust-axum uses). - handlers.mustache: replace `use crate::models::*;` with `use crate::models::{self, *};` so handler files also see the `models` module name (needed for `JsonBody<Vec<models::User>>` and similar). - models.mustache: merge the two `#[derive(...)]` lines, remove now-dead `hasEnums` block. Verified with the bundled petstore.yaml plus all three rust-salvo test specs — every generated project passes `cargo check` cleanly against salvo 0.93. The Java test suite (7 tests) still passes. * [rust-salvo] Align declared feature set with rust-axum and refresh docs - RustSalvoServerCodegen: claim allOf and anyOf alongside oneOf in schemaSupportFeatures so the generator advertises the same composite schema surface as rust-axum (now ✓ in the feature matrix). - Add docs/generators/rust-salvo.md (auto-generated via bin/utils/export_generator.sh), matching the structure of rust-axum.md / rust-server.md. - README.mustache: rewrite to reflect what the generator actually emits on Salvo 0.93 — the salvo::oapi::endpoint macro, the typed extractors from salvo::oapi::extract, ToSchema-derived models, the routes / handlers / middleware module layout, and re-generation flags for optional auth / CORS / validation. Drops stale wording about Salvo 1.70 and the previous middleware shape. - CLAUDE.md: replace the "in-progress" stub with an accurate snapshot of the rust-salvo generator's HEAD state and remaining axum-parity gaps. * [rust-salvo] Use Locale.ROOT for httpMethod.toLowerCase CI build failed forbiddenapis check at RustSalvoServerCodegen.java:332 and :337 because String#toLowerCase() relies on the JVM default locale and can produce wrong results under, e.g., the Turkish locale. Switch to toLowerCase(Locale.ROOT) and lift the value into a local so both call sites share the locale-safe form. Local `./mvnw verify` on modules/openapi-generator now passes the forbiddenapis scan with 0 errors, and the 7 RustSalvoServerCodegenTest cases still pass. * Remove CLAUDE.md from upstream branch CLAUDE.md is fork-local development guidance (kept on the fork's master) and should not be part of the upstream PR. * [rust-salvo] Generate sample server (petstore) Output of bin/configs/manual/rust-salvo-petstore.yaml. Verified with cargo check (clean) against Salvo 0.93. * [rust-salvo] Address PR review: per-op auth, serde rename, CI, README - Attach authentication as per-operation `.hoop(...)` on the route rather than a global service hoop, so public operations are no longer blocked by the generated middleware. - Emit one `security(("<scheme>" = []))` entry per scheme on `#[salvo::oapi::endpoint]`, matching OpenAPI OR-of-requirements semantics instead of collapsing alternatives into AND. - Add `#[serde(rename = "<wire>")]` to model fields whose Rust snake_case name diverges from the OpenAPI baseName so the JSON contract is preserved (petId, photoUrls, shipDate, …). - Make `Authorization` scheme prefix matching case-insensitive in the Basic/Bearer middleware via a shared helper. - Split the HTTP-scheme middleware emission into separate `isBasicBasic` / `isBasicBearer` paths so both BasicAuth and BearerAuth structs are generated, with matching per-route factory functions. - Backfill the auth test fixture with BasicAuth and a multi-scheme (OR) operation; tighten the codegen test to cover the new factories, per-route hoops, and serde renames. - Render the README's `## API endpoints` section from `apiInfo.apis`. - Add a dedicated `build-salvo` job to `samples-rust-server.yaml` so the rust-salvo sample is covered in CI alongside rust-server / rust-axum. * [rust-salvo] Preserve OAuth2 scopes in endpoint security annotation Pull the declared scopes from `CodegenSecurity.scopes` onto each Salvo auth scheme descriptor and render them inside the `#[salvo::oapi::endpoint(security(...))]` array. Previously every scheme was emitted with an empty `[]`, dropping the OAuth2 / OIDC authorization scopes from the OpenAPI source spec (e.g. `("OAuth2" = [])` → `("OAuth2" = ["write:pets", "read:pets"])`). * [rust-salvo] Move sample into shared rust-server CI matrix Add a top-level workspace Cargo.toml at samples/server/petstore/rust-salvo/ so the sample fits the same matrix shape as rust-server / rust-axum, then add it to the matrix list and drop the standalone build-salvo job. Per #23772 (comment) --------- Co-authored-by: root <962742249@qq.com>
1 parent 397645c commit 2114edc

37 files changed

Lines changed: 3223 additions & 0 deletions

.github/workflows/samples-rust-server.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ on:
55
paths:
66
- "samples/server/petstore/rust-server/**"
77
- "samples/server/petstore/rust-axum/**"
8+
- "samples/server/petstore/rust-salvo/**"
89
pull_request:
910
paths:
1011
- "samples/server/petstore/rust-server/**"
1112
- "samples/server/petstore/rust-axum/**"
13+
- "samples/server/petstore/rust-salvo/**"
1214

1315
jobs:
1416
build:
@@ -22,6 +24,7 @@ jobs:
2224
- samples/server/petstore/rust-server/
2325
- samples/server/petstore/rust-server-deprecated/
2426
- samples/server/petstore/rust-axum/
27+
- samples/server/petstore/rust-salvo/
2528
steps:
2629
- uses: actions/checkout@v5
2730
- uses: actions-rs/toolchain@v1
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
generatorName: rust-salvo
2+
outputDir: samples/server/petstore/rust-salvo/output/petstore
3+
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
4+
templateDir: modules/openapi-generator/src/main/resources/rust-salvo
5+
generateAliasAsModel: true
6+
additionalProperties:
7+
hideGenerationTimestamp: "true"
8+
packageName: petstore_salvo
9+
homePageUrl: https://github.com/openapitools/openapi-generator
10+
globalProperties:
11+
skipFormModel: false

docs/generators.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ The following generators are available:
147147
* [ruby-on-rails](generators/ruby-on-rails.md)
148148
* [ruby-sinatra](generators/ruby-sinatra.md)
149149
* [rust-axum (beta)](generators/rust-axum.md)
150+
* [rust-salvo (beta)](generators/rust-salvo.md)
150151
* [rust-server](generators/rust-server.md)
151152
* [rust-server-deprecated](generators/rust-server-deprecated.md)
152153
* [scala-akka-http-server (beta)](generators/scala-akka-http-server.md)

docs/generators/rust-salvo.md

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
---
2+
title: Documentation for the rust-salvo Generator
3+
---
4+
5+
## METADATA
6+
7+
| Property | Value | Notes |
8+
| -------- | ----- | ----- |
9+
| generator name | rust-salvo | pass this to the generate command after -g |
10+
| generator stability | BETA | |
11+
| generator type | SERVER | |
12+
| generator language | Rust | |
13+
| generator default templating engine | mustache | |
14+
| helpTxt | Generates a Rust server library using Salvo web framework. | |
15+
16+
## CONFIG OPTIONS
17+
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
18+
19+
| Option | Description | Values | Default |
20+
| ------ | ----------- | ------ | ------- |
21+
|enableAuthMiddleware|Enable authentication middleware| |false|
22+
|enableCorsMiddleware|Enable CORS middleware| |false|
23+
|enableRequestValidation|Enable request validation middleware| |true|
24+
|enableResponseValidation|Enable response validation middleware| |false|
25+
|packageName|Rust crate name (convention: snake_case).| |salvo_openapi|
26+
|packageVersion|Rust crate version.| |null|
27+
28+
## IMPORT MAPPING
29+
30+
| Type/Alias | Imports |
31+
| ---------- | ------- |
32+
33+
34+
## INSTANTIATION TYPES
35+
36+
| Type/Alias | Instantiated By |
37+
| ---------- | --------------- |
38+
|array|Vec|
39+
|map|std::collections::HashMap|
40+
41+
42+
## LANGUAGE PRIMITIVES
43+
44+
<ul class="column-ul">
45+
<li>String</li>
46+
<li>bool</li>
47+
<li>char</li>
48+
<li>f32</li>
49+
<li>f64</li>
50+
<li>i16</li>
51+
<li>i32</li>
52+
<li>i64</li>
53+
<li>i8</li>
54+
<li>isize</li>
55+
<li>str</li>
56+
<li>u16</li>
57+
<li>u32</li>
58+
<li>u64</li>
59+
<li>u8</li>
60+
<li>usize</li>
61+
</ul>
62+
63+
## RESERVED WORDS
64+
65+
<ul class="column-ul">
66+
<li>Self</li>
67+
<li>abstract</li>
68+
<li>as</li>
69+
<li>async</li>
70+
<li>await</li>
71+
<li>become</li>
72+
<li>box</li>
73+
<li>break</li>
74+
<li>const</li>
75+
<li>continue</li>
76+
<li>crate</li>
77+
<li>do</li>
78+
<li>dyn</li>
79+
<li>else</li>
80+
<li>enum</li>
81+
<li>extern</li>
82+
<li>false</li>
83+
<li>final</li>
84+
<li>fn</li>
85+
<li>for</li>
86+
<li>if</li>
87+
<li>impl</li>
88+
<li>in</li>
89+
<li>let</li>
90+
<li>loop</li>
91+
<li>macro</li>
92+
<li>match</li>
93+
<li>mod</li>
94+
<li>move</li>
95+
<li>mut</li>
96+
<li>override</li>
97+
<li>priv</li>
98+
<li>pub</li>
99+
<li>ref</li>
100+
<li>return</li>
101+
<li>self</li>
102+
<li>static</li>
103+
<li>struct</li>
104+
<li>super</li>
105+
<li>trait</li>
106+
<li>true</li>
107+
<li>try</li>
108+
<li>type</li>
109+
<li>typeof</li>
110+
<li>unsafe</li>
111+
<li>unsized</li>
112+
<li>use</li>
113+
<li>virtual</li>
114+
<li>where</li>
115+
<li>while</li>
116+
<li>yield</li>
117+
</ul>
118+
119+
## FEATURE SET
120+
121+
122+
### Client Modification Feature
123+
| Name | Supported | Defined By |
124+
| ---- | --------- | ---------- |
125+
|BasePath|✗|ToolingExtension
126+
|Authorizations|✗|ToolingExtension
127+
|UserAgent|✗|ToolingExtension
128+
|MockServer|✗|ToolingExtension
129+
130+
### Data Type Feature
131+
| Name | Supported | Defined By |
132+
| ---- | --------- | ---------- |
133+
|Custom|✗|OAS2,OAS3
134+
|Int32|✓|OAS2,OAS3
135+
|Int64|✓|OAS2,OAS3
136+
|Float|✓|OAS2,OAS3
137+
|Double|✓|OAS2,OAS3
138+
|Decimal|✓|ToolingExtension
139+
|String|✓|OAS2,OAS3
140+
|Byte|✓|OAS2,OAS3
141+
|Binary|✓|OAS2,OAS3
142+
|Boolean|✓|OAS2,OAS3
143+
|Date|✓|OAS2,OAS3
144+
|DateTime|✓|OAS2,OAS3
145+
|Password|✓|OAS2,OAS3
146+
|File|✓|OAS2
147+
|Uuid||
148+
|Array|✓|OAS2,OAS3
149+
|Null|✗|OAS3
150+
|AnyType|✗|OAS2,OAS3
151+
|Object|✓|OAS2,OAS3
152+
|Maps|✓|ToolingExtension
153+
|CollectionFormat|✓|OAS2
154+
|CollectionFormatMulti|✓|OAS2
155+
|Enum|✓|OAS2,OAS3
156+
|ArrayOfEnum|✓|ToolingExtension
157+
|ArrayOfModel|✓|ToolingExtension
158+
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
159+
|ArrayOfCollectionOfModel|✓|ToolingExtension
160+
|ArrayOfCollectionOfEnum|✓|ToolingExtension
161+
|MapOfEnum|✓|ToolingExtension
162+
|MapOfModel|✓|ToolingExtension
163+
|MapOfCollectionOfPrimitives|✓|ToolingExtension
164+
|MapOfCollectionOfModel|✓|ToolingExtension
165+
|MapOfCollectionOfEnum|✓|ToolingExtension
166+
167+
### Documentation Feature
168+
| Name | Supported | Defined By |
169+
| ---- | --------- | ---------- |
170+
|Readme|✗|ToolingExtension
171+
|Model|✓|ToolingExtension
172+
|Api|✓|ToolingExtension
173+
174+
### Global Feature
175+
| Name | Supported | Defined By |
176+
| ---- | --------- | ---------- |
177+
|Host|✓|OAS2,OAS3
178+
|BasePath|✓|OAS2,OAS3
179+
|Info|✗|OAS2,OAS3
180+
|Schemes|✗|OAS2,OAS3
181+
|PartialSchemes|✓|OAS2,OAS3
182+
|Consumes|✓|OAS2
183+
|Produces|✓|OAS2
184+
|ExternalDocumentation|✗|OAS2,OAS3
185+
|Examples|✗|OAS2,OAS3
186+
|XMLStructureDefinitions|✗|OAS2,OAS3
187+
|MultiServer|✗|OAS3
188+
|ParameterizedServer|✗|OAS3
189+
|ParameterStyling|✗|OAS3
190+
|Callbacks|✗|OAS3
191+
|LinkObjects|✗|OAS3
192+
193+
### Parameter Feature
194+
| Name | Supported | Defined By |
195+
| ---- | --------- | ---------- |
196+
|Path|✓|OAS2,OAS3
197+
|Query|✓|OAS2,OAS3
198+
|Header|✓|OAS2,OAS3
199+
|Body|✓|OAS2
200+
|FormUnencoded|✓|OAS2
201+
|FormMultipart|✓|OAS2
202+
|Cookie|✓|OAS3
203+
204+
### Schema Support Feature
205+
| Name | Supported | Defined By |
206+
| ---- | --------- | ---------- |
207+
|Simple|✓|OAS2,OAS3
208+
|Composite|✓|OAS2,OAS3
209+
|Polymorphism|✗|OAS2,OAS3
210+
|Union|✗|OAS3
211+
|allOf|✓|OAS2,OAS3
212+
|anyOf|✓|OAS3
213+
|oneOf|✓|OAS3
214+
|not|✗|OAS3
215+
216+
### Security Feature
217+
| Name | Supported | Defined By |
218+
| ---- | --------- | ---------- |
219+
|BasicAuth|✓|OAS2,OAS3
220+
|ApiKey|✓|OAS2,OAS3
221+
|OpenIDConnect|✗|OAS3
222+
|BearerToken|✓|OAS3
223+
|OAuth2_Implicit|✗|OAS2,OAS3
224+
|OAuth2_Password|✗|OAS2,OAS3
225+
|OAuth2_ClientCredentials|✗|OAS2,OAS3
226+
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
227+
|SignatureAuth|✗|OAS3
228+
|AWSV4Signature|✗|ToolingExtension
229+
230+
### Wire Format Feature
231+
| Name | Supported | Defined By |
232+
| ---- | --------- | ---------- |
233+
|JSON|✓|OAS2,OAS3
234+
|XML|✗|OAS2,OAS3
235+
|PROTOBUF|✗|ToolingExtension
236+
|Custom|✓|OAS2,OAS3

0 commit comments

Comments
 (0)