1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use poem::{
http::{header::HeaderName, HeaderMap, HeaderValue, StatusCode},
Error, IntoResponse,
};
use crate::{
registry::{MetaResponses, Registry},
ApiResponse,
};
/// A response type wrapper.
///
/// Use it to modify the status code and HTTP headers.
///
/// # Examples
///
/// ```
/// use poem::{
/// error::BadRequest,
/// http::{Method, StatusCode, Uri},
/// test::TestClient,
/// Body, IntoEndpoint, Request, Result,
/// };
/// use poem_openapi::{
/// payload::{Json, Response},
/// OpenApi, OpenApiService,
/// };
/// use tokio::io::AsyncReadExt;
///
/// struct MyApi;
///
/// #[OpenApi]
/// impl MyApi {
/// #[oai(path = "/test", method = "get")]
/// async fn test(&self) -> Response<Json<i32>> {
/// Response::new(Json(100)).header("foo", "bar")
/// }
/// }
///
/// let api = OpenApiService::new(MyApi, "Demo", "0.1.0");
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let resp = TestClient::new(api).get("/test").send().await;
/// resp.assert_status_is_ok();
/// resp.assert_header("foo", "bar");
/// resp.assert_text("100").await;
/// # });
/// ```
pub struct Response<T> {
inner: T,
status: Option<StatusCode>,
headers: HeaderMap,
}
impl<T> Response<T> {
/// Create a response object.
#[must_use]
pub fn new(resp: T) -> Self {
Self {
inner: resp,
status: None,
headers: HeaderMap::new(),
}
}
/// Sets the HTTP status for this response.
#[must_use]
pub fn status(self, status: StatusCode) -> Self {
Self {
status: Some(status),
..self
}
}
/// Appends a header to this response.
#[must_use]
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
K: TryInto<HeaderName>,
V: TryInto<HeaderValue>,
{
let key = key.try_into();
let value = value.try_into();
if let (Ok(key), Ok(value)) = (key, value) {
self.headers.append(key, value);
}
self
}
}
impl<T: IntoResponse> IntoResponse for Response<T> {
fn into_response(self) -> poem::Response {
let mut resp = self.inner.into_response();
if let Some(status) = self.status {
resp.set_status(status);
}
resp.headers_mut().extend(self.headers);
resp
}
}
impl<T: ApiResponse> ApiResponse for Response<T> {
const BAD_REQUEST_HANDLER: bool = T::BAD_REQUEST_HANDLER;
fn meta() -> MetaResponses {
T::meta()
}
fn register(registry: &mut Registry) {
T::register(registry);
}
fn from_parse_request_error(err: Error) -> Self {
Self::new(T::from_parse_request_error(err))
}
}