use actix_web::http::StatusCode;
use actix_web::{web::ServiceConfig, FromRequest, HttpResponse, ResponseError};
use serde::Serialize;
use std::{
fmt::{self, Debug, Display, Formatter},
ops,
};
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{#-last}}
pub use crate::apis::{{{classFilename}}}::actix::server::{{{classname}}};
{{/-last}}
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
/// Rest Error wrapper with a status code and a JSON error
/// Note: Only a single error type for each handler is supported at the moment
pub struct RestError<T: Debug + Serialize> {
status_code: StatusCode,
error_response: T,
}
impl<T: Debug + Serialize> RestError<T> {
pub fn new(status_code: StatusCode, error_response: T) -> Self {
Self {
status_code,
error_response
}
}
}
impl<T: Debug + Serialize> Debug for RestError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("RestError")
.field("status_code", &self.status_code)
.field("error_response", &self.error_response)
.finish()
}
}
impl<T: Debug + Serialize> Display for RestError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl<T: Debug + Serialize> ResponseError for RestError<T> {
fn status_code(&self) -> StatusCode {
self.status_code
}
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status_code).json(&self.error_response)
}
}
/// 204 Response with no content
#[derive(Default)]
pub(crate) struct NoContent;
impl From<actix_web::web::Json<()>> for NoContent {
fn from(_: actix_web::web::Json<()>) -> Self {
NoContent {}
}
}
impl From<()> for NoContent {
fn from(_: ()) -> Self {
NoContent {}
}
}
impl actix_web::Responder for NoContent {
{{^actixWeb4Beta}}type Body = actix_web::body::BoxBody;{{/actixWeb4Beta}}
fn respond_to(self, _: &actix_web::HttpRequest) -> actix_web::HttpResponse {
actix_web::HttpResponse::NoContent().finish()
}
}
/// Wrapper type used as tag to easily distinguish the 3 different parameter types:
/// 1. Path 2. Query 3. Body
/// Example usage:
/// fn delete_resource(Path((p1, p2)): Path<(String, u64)>) { ... }
pub struct Path<T>(pub T);
impl<T> Path<T> {
/// Deconstruct to an inner value
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> AsRef<T> for Path<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> ops::Deref for Path<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> ops::DerefMut for Path<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
/// Wrapper type used as tag to easily distinguish the 3 different parameter types:
/// 1. Path 2. Query 3. Body
/// Example usage:
/// fn delete_resource(Path((p1, p2)): Path<(String, u64)>) { ... }
pub struct Query<T>(pub T);
impl<T> Query<T> {
/// Deconstruct to an inner value
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> AsRef<T> for Query<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> ops::Deref for Query<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> ops::DerefMut for Query<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
/// Wrapper type used as tag to easily distinguish the 3 different parameter types:
/// 1. Path 2. Query 3. Body
/// Example usage:
/// fn delete_resource(Path((p1, p2)): Path<(String, u64)>) { ... }
pub struct Body<T>(pub T);
impl<T> Body<T> {
/// Deconstruct to an inner value
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> AsRef<T> for Body<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> ops::Deref for Body<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T> ops::DerefMut for Body<T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.0
}
}
/// Configure all actix server handlers
pub fn configure<T: {{#apiInfo}}{{#apis}}{{#operations}}{{^-last}}{{{classname}}} + {{/-last}}{{#-last}}{{{classname}}} + 'static{{#hasAuthMethods}}, A: FromRequest + 'static{{/hasAuthMethods}}{{/-last}}{{/operations}}{{/apis}}{{/apiInfo}}>(cfg: &mut ServiceConfig) {
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{#operation}}
{{#-last}}
crate::apis::{{{classFilename}}}::actix::server::handlers::configure::<T{{#hasAuthMethods}}, A{{/hasAuthMethods}}>(cfg);
{{/-last}}
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
}
/// Used with Query to deserialize into Vec<I>.
#[allow(dead_code)]
pub(crate) fn deserialize_stringified_list<'de, D, I>(
deserializer: D,
) -> std::result::Result<Vec<I>, D::Error>
where
D: serde::de::Deserializer<'de>,
I: serde::de::DeserializeOwned,
{
struct StringVecVisitor<I>(std::marker::PhantomData<I>);
impl<'de, I> serde::de::Visitor<'de> for StringVecVisitor<I>
where
I: serde::de::DeserializeOwned,
{
type Value = Vec<I>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a string containing a list")
}
fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
where
E: serde::de::Error,
{
let mut list = Vec::new();
if !v.is_empty() {
for item in v.split(',') {
let item = I::deserialize(serde::de::IntoDeserializer::into_deserializer(item))?;
list.push(item);
}
}
Ok(list)
}
}
deserializer.deserialize_any(StringVecVisitor(std::marker::PhantomData::<I>))
}
/// Used with Query to deserialize into Option<Vec<I>>.
#[allow(dead_code)]
pub(crate) fn deserialize_option_stringified_list<'de, D, I>(
deserializer: D,
) -> std::result::Result<Option<Vec<I>>, D::Error>
where
D: serde::de::Deserializer<'de>,
I: serde::de::DeserializeOwned,
{
let list = deserialize_stringified_list(deserializer)?;
match list.is_empty() {
true => Ok(None),
false => Ok(Some(list)),
}
}