use super::layout::Uses;
use crate::ApiFramework;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Status {
Ok,
Created,
}
impl Status {
fn actix(self) -> &'static str {
match self {
Status::Ok => "Ok",
Status::Created => "Created",
}
}
}
pub struct Extracted {
param: String,
value: String,
import: Option<&'static str>,
}
impl Extracted {
pub fn value(&self) -> &str {
&self.value
}
pub fn param(&self, uses: &mut Uses) -> String {
if let Some(import) = self.import {
uses.add(import);
}
self.param.clone()
}
pub fn push_let(&self, output: &mut String, binding: &str) {
if self.value != binding {
output.push_str(&format!(" let {binding} = {};\n", self.value));
}
}
}
impl ApiFramework {
pub(super) fn handler_uses(self, uses: &mut Uses) {
match self {
ApiFramework::Actix => {
uses.add("actix_web::HttpResponse");
uses.add("actix_web::web");
}
ApiFramework::Axum => {
uses.add("axum::extract::State");
uses.add("axum::response::IntoResponse");
uses.add("axum::response::Response");
uses.add("std::sync::Arc");
}
}
}
pub(super) fn service_param(self, service: &str) -> String {
match self {
ApiFramework::Actix => format!("service: web::Data<{service}>"),
ApiFramework::Axum => format!("State(service): State<Arc<{service}>>"),
}
}
pub(super) fn path(self, binding: &str, ty: &str) -> Extracted {
match self {
ApiFramework::Actix => Extracted {
param: format!("path: web::Path<{ty}>"),
value: "path.into_inner()".to_owned(),
import: None,
},
ApiFramework::Axum => Extracted {
param: format!("Path({binding}): Path<{ty}>"),
value: binding.to_owned(),
import: Some("crate::shared::validation::Path"),
},
}
}
pub(super) fn query(self, ty: &str) -> Extracted {
match self {
ApiFramework::Actix => Extracted {
param: format!("query: web::Query<{ty}>"),
value: "query.into_inner()".to_owned(),
import: None,
},
ApiFramework::Axum => Extracted {
param: format!("Query(query): Query<{ty}>"),
value: "query".to_owned(),
import: Some("crate::shared::validation::Query"),
},
}
}
pub(super) fn returns(self) -> &'static str {
match self {
ApiFramework::Actix => "Result<HttpResponse, AppError>",
ApiFramework::Axum => "Result<Response, AppError>",
}
}
pub(super) fn push_answer(
self,
output: &mut String,
uses: &mut Uses,
status: Status,
headers: &[&str],
body: &str,
) {
match self {
ApiFramework::Actix => push_actix_answer(output, uses, status, headers, body),
ApiFramework::Axum => push_axum_answer(output, uses, status, headers, body),
}
}
pub(super) fn push_no_content(self, output: &mut String, uses: &mut Uses) {
match self {
ApiFramework::Actix => output.push_str(" Ok(HttpResponse::NoContent().finish())\n"),
ApiFramework::Axum => {
uses.add("axum::http::StatusCode");
output.push_str(" Ok(StatusCode::NO_CONTENT.into_response())\n");
}
}
}
}
fn push_actix_answer(
output: &mut String,
uses: &mut Uses,
status: Status,
headers: &[&str],
body: &str,
) {
let status = status.actix();
if headers.is_empty() {
output.push_str(&format!(" Ok(HttpResponse::{status}().json({body}))\n"));
return;
}
uses.add("actix_web::http::header");
output.push_str(&format!(" Ok(HttpResponse::{status}()\n"));
for header in headers {
output.push_str(&format!(" .insert_header({header})\n"));
}
output.push_str(&format!(" .json({body}))\n"));
}
fn push_axum_answer(
output: &mut String,
uses: &mut Uses,
status: Status,
headers: &[&str],
body: &str,
) {
uses.add("axum::Json");
let mut parts = Vec::new();
if status == Status::Created {
uses.add("axum::http::StatusCode");
parts.push("StatusCode::CREATED".to_owned());
}
if !headers.is_empty() {
uses.add("axum::http::header");
output.push_str(&format!(" let headers = [{}];\n", headers.join(", ")));
parts.push("headers".to_owned());
}
if parts.is_empty() {
output.push_str(&format!(" Ok(Json({body}).into_response())\n"));
return;
}
parts.push(format!("Json({body})"));
output.push_str(&format!(" let answer = ({});\n", parts.join(", ")));
output.push_str(" Ok(answer.into_response())\n");
}