Skip to content

Instantly share code, notes, and snippets.

@banool
Created September 9, 2022 00:07
mod mymacro;
use anyhow::format_err;
use indoc::indoc;
use poem::listener::TcpListener;
use poem::{Route, Server};
use poem_openapi::payload::Json;
use poem_openapi::{Object, OpenApi, OpenApiService, Union};
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
#[derive(Clone, Debug, Default, Eq, PartialEq, Copy)]
pub struct U64(u64);
impl FromStr for U64 {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let data = s.parse::<u64>().map_err(|e| {
format_err!("Parsing u64 string {:?} failed, caused by error: {}", s, e)
})?;
Ok(U64(data))
}
}
impl Serialize for U64 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.to_string().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for U64 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
s.parse().map_err(D::Error::custom)
}
}
impl_poem_type!(
U64,
"string",
(
example = Some(serde_json::Value::String("32425224034".to_string())),
format = Some("uint64"),
description = Some(indoc! {"
A string containing a 64-bit unsigned integer.
We represent u64 values as a string to ensure compatibility with languages such
as JavaScript that do not parse u64s in JSON natively.
"})
)
);
#[derive(Debug, Object)]
pub struct MyStruct {
/// some docs
pub public_key: String,
// if you make this a doc string, this field becomes allof
pub number: U64,
}
#[derive(Debug, Union)]
#[oai(one_of, discriminator_name = "type", rename_all = "snake_case")]
pub enum AccountSignature {
MyStruct(MyStruct),
}
struct MyApi;
#[OpenApi]
impl MyApi {
#[oai(path = "/test", method = "get")]
async fn test(&self) -> Json<AccountSignature> {
Json(AccountSignature::MyStruct(MyStruct {
public_key: "test".to_string(),
number: U64(5),
}))
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api_service = OpenApiService::new(MyApi, "My API", "0.1.0").description("My API");
let spec_yaml = api_service.spec_endpoint_yaml();
let route = Route::new()
.nest("/", api_service)
.at("/spec.yaml", spec_yaml);
Ok(Server::new(TcpListener::bind(("127.0.0.1", 8888)))
.run(route)
.await?)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment