feat: add shared API operation metadata macro

This commit is contained in:
2026-09-17 23:05:11 +09:00
parent 96592b1a24
commit 9590cf332d
28 changed files with 1384 additions and 0 deletions
@@ -0,0 +1,11 @@
use api_macros::api;
pub struct Response;
#[api]
pub trait AnonymousBody {
#[post("/widgets")]
async fn create(&self, #[body] request: (u64, u64)) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: request bodies must use a named Rust type
--> tests/ui/anonymous_body.rs:8:45
|
8 | async fn create(&self, #[body] request: (u64, u64)) -> Response;
| ^^^^^^^^^^
@@ -0,0 +1,14 @@
use api_macros::api;
pub struct Response;
#[api]
pub trait DuplicateOperationId {
#[get("/one", operation_id = "duplicate")]
async fn one(&self) -> Response;
#[get("/two", operation_id = "duplicate")]
async fn two(&self) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: duplicate operation ID `duplicate`
--> tests/ui/duplicate_operation_id.rs:11:14
|
11 | async fn two(&self) -> Response;
| ^^^
@@ -0,0 +1,14 @@
use api_macros::api;
pub struct Response;
#[api]
pub trait DuplicateRoute {
#[get("/widgets", operation_id = "widgets.first")]
async fn first(&self) -> Response;
#[get("/widgets", operation_id = "widgets.second")]
async fn second(&self) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: duplicate route for GET `/widgets`
--> tests/ui/duplicate_route.rs:11:14
|
11 | async fn second(&self) -> Response;
| ^^^^^^
@@ -0,0 +1,12 @@
use api_macros::api;
pub struct Response;
pub struct PublicError;
#[api]
pub trait InvalidErrorStatus {
#[get("/widgets", error_status = 200)]
async fn list(&self) -> Result<Response, PublicError>;
}
fn main() {}
@@ -0,0 +1,5 @@
error: error_status must be between 400 and 599
--> tests/ui/invalid_error_status.rs:8:38
|
8 | #[get("/widgets", error_status = 200)]
| ^^^
@@ -0,0 +1,12 @@
use api_macros::api;
pub struct Request;
pub struct Response;
#[api]
pub trait InvalidMethodBody {
#[get("/widgets")]
async fn list(&self, #[body] request: Request) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: GET operations cannot declare a request body
--> tests/ui/invalid_method_body.rs:9:14
|
9 | async fn list(&self, #[body] request: Request) -> Response;
| ^^^^
@@ -0,0 +1,11 @@
use api_macros::api;
pub struct Response;
#[api]
pub trait InvalidSuccessStatus {
#[get("/widgets", status = 404)]
async fn list(&self) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: status must be a success status between 200 and 299
--> tests/ui/invalid_success_status.rs:7:32
|
7 | #[get("/widgets", status = 404)]
| ^^^
@@ -0,0 +1,17 @@
use api_macros::api;
pub struct FirstBody;
pub struct SecondBody;
pub struct Response;
#[api]
pub trait MultipleBodies {
#[post("/widgets")]
async fn create(
&self,
#[body] first: FirstBody,
#[body] second: SecondBody,
) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: an API operation may declare only one request body
--> tests/ui/multiple_bodies.rs:13:17
|
13 | #[body] second: SecondBody,
| ^^^^^^
@@ -0,0 +1,11 @@
use api_macros::api;
pub struct Response;
#[api]
pub trait PathMismatch {
#[get("/widgets/{widget_id}")]
async fn get(&self, #[path] other_id: u64) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: path placeholder(s) have no matching path parameter: widget_id
--> tests/ui/path_mismatch.rs:7:11
|
7 | #[get("/widgets/{widget_id}")]
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -0,0 +1,14 @@
#![allow(async_fn_in_trait, private_interfaces)]
use api_macros::api;
struct PrivateRequest;
pub struct Response;
#[api]
pub trait PrivateBody {
#[post("/widgets")]
async fn create(&self, #[body] request: PrivateRequest) -> Response;
}
fn main() {}
@@ -0,0 +1,10 @@
error[E0446]: private type `PrivateRequest` in public interface
--> tests/ui/private_body.rs:8:1
|
5 | struct PrivateRequest;
| --------------------- `PrivateRequest` declared as private
...
8 | #[api]
| ^^^^^^ can't leak private type
|
= note: this error originates in the attribute macro `api` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -0,0 +1,12 @@
use api_macros::api;
pub struct StreamRequest;
pub struct Response;
#[api]
pub trait UnsupportedWireKind {
#[post("/widgets")]
async fn create(&self, #[stream] request: StreamRequest) -> Response;
}
fn main() {}
@@ -0,0 +1,5 @@
error: this wire kind is explicitly unsupported by the initial API contract
--> tests/ui/unsupported_wire_kind.rs:9:28
|
9 | async fn create(&self, #[stream] request: StreamRequest) -> Response;
| ^^^^^^^^^