Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/zihantype/poem-extensions
为Poem框架添加扩展功能 -- Add some extensions to Poem web framework
https://github.com/zihantype/poem-extensions
openapi rust
Last synced: about 1 month ago
JSON representation
为Poem框架添加扩展功能 -- Add some extensions to Poem web framework
- Host: GitHub
- URL: https://github.com/zihantype/poem-extensions
- Owner: ZihanType
- License: mit
- Created: 2022-05-30T02:08:36.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-05-06T07:10:23.000Z (6 months ago)
- Last Synced: 2024-09-28T13:22:05.749Z (about 2 months ago)
- Topics: openapi, rust
- Language: Rust
- Homepage:
- Size: 57.6 KB
- Stars: 5
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# poem-extensions
[![Crates.io version](https://img.shields.io/crates/v/poem-extensions.svg?style=flat-square)](https://crates.io/crates/poem-extensions)
Add some extensions to Poem web framework.
## `UniOpenApi`, `api`
`UniOpenApi` unifies multiple `struct`s that implement [`OpenApi`](https://docs.rs/poem-openapi/latest/poem_openapi/attr.OpenApi.html) into one `struct`. Because using the [`OpenApiService::new()`](https://docs.rs/poem-openapi/latest/poem_openapi/struct.OpenApiService.html#method.new) method can only convert a tuple with at most 16 elements into an [`Endpoint`](https://docs.rs/poem/latest/poem/endpoint/trait.Endpoint.html#), `UniOpenApi` is available to facilitate developers to define an unlimited number of `OpenApi` implementations. `api` is a simplified version of `UniOpenApi`, combining declaration and invocation into one.
### Example
#### before
```rust
use poem_openapi::{OpenApi, OpenApiService};struct Api1;
#[OpenApi]
impl Api1 {}struct Api2;
#[OpenApi]
impl Api2 {}struct Api3;
#[OpenApi]
impl Api3 {}/// only put a maximum of 16 OpenApi struct
let api = (Api1, Api2, Api3);let api_service = OpenApiService::new(api, "Combined APIs", "1.0")
.server("http://localhost:3000/api");
```#### after
```rust
use poem_extensions::{api, UniOpenApi};
use poem_openapi::{OpenApi, OpenApiService};struct Api1;
#[OpenApi]
impl Api1 {}struct Api2;
#[OpenApi]
impl Api2 {}struct Api3;
#[OpenApi]
impl Api3 {}/// struct mode, support generics
#[derive(UniOpenApi)]
struct Union(Api1, Api2, Api3);let api = Union(Api1, Api2, Api3);
/// ... or tuple mode, not support generics
let api = api!(Api1, Api2, Api3);let api_service = OpenApiService::new(api, "Combined APIs", "1.0")
.server("http://localhost:3000/api");
```## `OneResponse`, `UniResponse`, `response`
The response type defined by [ApiResponse](https://docs.rs/poem-openapi/latest/poem_openapi/derive.ApiResponse.html) has too much control granularity and is less reusable. Either one request defines one response, which is too much code, or it defines a response that contains all possible responses, which can obscure the really important ones.
Because of such shortcomings, 3 helpers are provided in this repository.
- `OneResponse` is a simplification of `ApiResponse`, where only one response type corresponding to one status code can be defined.
- `UniResponse` is an `enum` with 60 generic type slots corresponding to 60 response status codes.
- `response` is a functional macro for insert response type that defined by `OneResponse` into `UniResponse` type slots.### Example
#### before
```rust
use poem_openapi::{param::Query, ApiResponse, OpenApi};#[derive(ApiResponse)]
enum FirstResp {
#[oai(status = 200)]
Ok,
#[oai(status = 400)]
BadRequest,
}#[derive(ApiResponse)]
enum SecondResp {
#[oai(status = 200)]
Ok,
#[oai(status = 400)]
BadRequest,
#[oai(status = 404)]
NotFound,
}struct Api;
#[OpenApi]
impl Api {
#[oai(path = "/first", method = "get")]
async fn first(&self, name: Query>) -> FirstResp {
match name.0 {
Some(_) => FirstResp::Ok,
None => FirstResp::BadRequest,
}
}#[oai(path = "/second", method = "get")]
async fn second(&self, name: Query>) -> SecondResp {
match name.0 {
Some(a) if a > 100 => SecondResp::NotFound,
Some(_) => SecondResp::Ok,
None => SecondResp::BadRequest,
}
}
}
```#### after
```rust
use poem::IntoResponse;
use poem_extensions::{
response, OneResponse,
UniResponse::{T200, T400, T404},
};
use poem_openapi::{
param::Query,
payload::{Payload, PlainText},
OpenApi,
};#[derive(OneResponse)]
#[oai(status = 400)]
struct BadRequest(T);#[derive(OneResponse)]
#[oai(status = 404)]
struct NotFound;struct Api;
#[OpenApi]
impl Api {
#[oai(path = "/first", method = "get")]
async fn first(
&self,
name: Query>,
) -> response! {
200: PlainText,
400: BadRequest>,
} {
match name.0 {
Some(a) => T200(PlainText(format!("{}", a))),
None => T400(BadRequest(PlainText("name is required".to_string()))),
}
}#[oai(path = "/second", method = "get")]
async fn second(
&self,
name: Query>,
) -> response! {
200: (),
400: BadRequest>,
404: NotFound,
} {
match name.0 {
Some(a) if a > 100 => T404(NotFound),
Some(_) => T200(()),
None => T400(BadRequest(PlainText("name is required".to_string()))),
}
}
}
```## Contributing
Thanks for your help improving the project! We are so happy to have you!