♻️ Migra API pública de actix-web a Axum
- `configure_service` como `configure_router(Router) -> Router`. - Macro `static_files_service!` como `serve_static_files!`. - `ResultPage<M, E>` eliminado; handlers devuelven `Result<M, E>`. - `ErrorPage` implementa `IntoResponse` en lugar de `ResponseError`. - Registro con `OnceLock`; eliminados `drop_extensions` y `app.welcome`. - `Redirect` devuelve `Response`; docs y ejemplos actualizados.
This commit is contained in:
parent
019961ed77
commit
c1afe0e70c
30 changed files with 393 additions and 355 deletions
|
|
@ -1,4 +1,4 @@
|
|||
//! Extractor y generador de respuestas JSON (reexporta [`actix_web::web::Json`]).
|
||||
//! Extractor y generador de respuestas JSON (reexporta [`axum::Json`]).
|
||||
//!
|
||||
//! # Uso como extractor JSON
|
||||
//!
|
||||
|
|
@ -11,10 +11,10 @@
|
|||
//! struct NuevoUsuario { nombre: String, email: String }
|
||||
//!
|
||||
//! /// Manejador configurado para la ruta POST "/usuarios".
|
||||
//! async fn crear_usuario(payload: Json<NuevoUsuario>) -> HttpResponse {
|
||||
//! async fn crear_usuario(payload: Json<NuevoUsuario>) -> web::http::StatusCode {
|
||||
//! // `payload` ya es `NuevoUsuario`; si la deserialización falla,
|
||||
//! // devolverá automáticamente 400 Bad Request con un cuerpo JSON que describe el error.
|
||||
//! HttpResponse::Ok().finish()
|
||||
//! // devolverá automáticamente 400 Bad Request.
|
||||
//! web::http::StatusCode::OK
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
|
@ -36,4 +36,4 @@
|
|||
//! `Json<T>` funciona con cualquier tipo que implemente `serde::Serialize` (para respuestas) y/o
|
||||
//! `serde::Deserialize` (para peticiones).
|
||||
|
||||
pub use actix_web::web::Json;
|
||||
pub use axum::Json;
|
||||
|
|
|
|||
|
|
@ -16,18 +16,16 @@
|
|||
mod error;
|
||||
pub use error::ErrorPage;
|
||||
|
||||
pub use actix_web::Result as ResultPage;
|
||||
|
||||
use crate::base::action;
|
||||
use crate::core::component::{AssetsOp, ChildOp, Context, ContextError, Contextual};
|
||||
use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef};
|
||||
use crate::html::{html, Markup, DOCTYPE};
|
||||
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
|
||||
use crate::html::{Attr, AttrId};
|
||||
use crate::html::{Classes, ClassesOp};
|
||||
use crate::html::{DOCTYPE, Markup, html};
|
||||
use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier};
|
||||
use crate::service::HttpRequest;
|
||||
use crate::{builder_fn, AutoDefault};
|
||||
use crate::web::HttpRequest;
|
||||
use crate::{AutoDefault, builder_fn};
|
||||
|
||||
// **< ReservedRegion >*****************************************************************************
|
||||
|
||||
|
|
@ -227,8 +225,8 @@ impl Page {
|
|||
/// [`Context::langid()`](crate::core::component::Context::langid) e inserta los atributos
|
||||
/// `lang` y `dir` en la etiqueta `<html>`.
|
||||
/// 8. Compone el documento HTML completo (`<!DOCTYPE html>`, `<html>`, `<head>`, `<body>`) y
|
||||
/// devuelve un [`ResultPage`] con el [`Markup`] final.
|
||||
pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> {
|
||||
/// devuelve un [`Result`] con el [`Markup`] final.
|
||||
pub fn render(&mut self) -> Result<Markup, ErrorPage> {
|
||||
// Acciones específicas del tema antes de renderizar el <body>.
|
||||
self.context.theme().before_render_page_body(self);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use crate::core::component::Contextual;
|
||||
use crate::locale::L10n;
|
||||
use crate::response::ResponseError;
|
||||
use crate::service::http::{header::ContentType, StatusCode};
|
||||
use crate::service::{HttpRequest, HttpResponse};
|
||||
use crate::util;
|
||||
use crate::web::{HttpRequest, IntoResponse, Response, http};
|
||||
|
||||
use super::Page;
|
||||
|
||||
|
|
@ -31,13 +29,9 @@ pub enum ErrorPage {
|
|||
}
|
||||
|
||||
impl ErrorPage {
|
||||
/// Función auxiliar para renderizar una página de error genérica usando el tema activo.
|
||||
///
|
||||
/// Construye una [`Page`] a partir de la petición y un prefijo de clave basado en el código de
|
||||
/// estado (`error<code>`), del que se derivan los textos localizados `error<code>_title`,
|
||||
/// `error<code>_alert` y `error<code>_help`.
|
||||
///
|
||||
/// Si el renderizado falla, escribe en su lugar el texto plano asociado al código de estado.
|
||||
// Renderiza una página de error genérica usando el tema activo. Deriva las claves de
|
||||
// localización del código de estado (`error<code>_title`, `_alert`, `_help`). Si el
|
||||
// renderizado falla, escribe el texto plano del código de estado.
|
||||
fn display_error_page(&self, f: &mut fmt::Formatter<'_>, request: &HttpRequest) -> fmt::Result {
|
||||
let mut page = Page::new(request.clone());
|
||||
let code = self.status_code();
|
||||
|
|
@ -51,7 +45,19 @@ impl ErrorPage {
|
|||
if let Ok(rendered) = page.render() {
|
||||
write!(f, "{}", rendered.into_string())
|
||||
} else {
|
||||
f.write_str(&code.to_string())
|
||||
f.write_str(code.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Devuelve el código de estado HTTP asociado a la variante de error.
|
||||
pub fn status_code(&self) -> http::StatusCode {
|
||||
match self {
|
||||
ErrorPage::BadRequest(_) => http::StatusCode::BAD_REQUEST,
|
||||
ErrorPage::AccessDenied(_) => http::StatusCode::FORBIDDEN,
|
||||
ErrorPage::NotFound(_) => http::StatusCode::NOT_FOUND,
|
||||
ErrorPage::InternalError(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ErrorPage::ServiceUnavailable(_) => http::StatusCode::SERVICE_UNAVAILABLE,
|
||||
ErrorPage::GatewayTimeout(_) => http::StatusCode::GATEWAY_TIMEOUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +75,7 @@ impl fmt::Display for ErrorPage {
|
|||
if let Ok(rendered) = page.render() {
|
||||
write!(f, "{}", rendered.into_string())
|
||||
} else {
|
||||
f.write_str(&self.status_code().to_string())
|
||||
f.write_str(self.status_code().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +86,7 @@ impl fmt::Display for ErrorPage {
|
|||
if let Ok(rendered) = page.render() {
|
||||
write!(f, "{}", rendered.into_string())
|
||||
} else {
|
||||
f.write_str(&self.status_code().to_string())
|
||||
f.write_str(self.status_code().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,22 +102,17 @@ impl fmt::Display for ErrorPage {
|
|||
}
|
||||
}
|
||||
|
||||
impl ResponseError for ErrorPage {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(self.status_code())
|
||||
.insert_header(ContentType::html())
|
||||
.body(self.to_string())
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
ErrorPage::BadRequest(_) => StatusCode::BAD_REQUEST,
|
||||
ErrorPage::AccessDenied(_) => StatusCode::FORBIDDEN,
|
||||
ErrorPage::NotFound(_) => StatusCode::NOT_FOUND,
|
||||
ErrorPage::InternalError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ErrorPage::ServiceUnavailable(_) => StatusCode::SERVICE_UNAVAILABLE,
|
||||
ErrorPage::GatewayTimeout(_) => StatusCode::GATEWAY_TIMEOUT,
|
||||
}
|
||||
/// Convierte un [`ErrorPage`] en una respuesta HTTP con el código de estado adecuado y el cuerpo
|
||||
/// HTML generado por el tema activo.
|
||||
impl IntoResponse for ErrorPage {
|
||||
fn into_response(self) -> Response {
|
||||
let status = self.status_code();
|
||||
let body = self.to_string();
|
||||
(
|
||||
status,
|
||||
[(http::header::CONTENT_TYPE, "text/html; charset=utf-8")],
|
||||
body,
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@
|
|||
//!
|
||||
//! - **Respuestas especiales**.
|
||||
|
||||
use crate::service::HttpResponse;
|
||||
use crate::web::{IntoResponse, Response, http};
|
||||
|
||||
/// Funciones predefinidas para generar respuestas HTTP de redirección.
|
||||
///
|
||||
/// Ofrece atajos para construir respuestas con el código de estado apropiado, añade la cabecera
|
||||
/// `Location` y la cierra con `.finish()`, evitando repetir la misma secuencia en cada controlador.
|
||||
/// Ofrece atajos para construir respuestas con el código de estado apropiado y la cabecera
|
||||
/// `Location`, evitando repetir la misma secuencia en cada controlador.
|
||||
pub struct Redirect;
|
||||
|
||||
impl Redirect {
|
||||
|
|
@ -34,10 +34,12 @@ impl Redirect {
|
|||
/// Emplear cuando un recurso se ha movido de forma definitiva y la URL antigua debe dejar de
|
||||
/// usarse.
|
||||
#[must_use]
|
||||
pub fn moved(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::MovedPermanently()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
pub fn moved(redirect_to_url: &str) -> Response {
|
||||
(
|
||||
http::StatusCode::MOVED_PERMANENTLY,
|
||||
[(http::header::LOCATION, redirect_to_url.to_owned())],
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
/// Redirección **permanente**. Código de estado **308**. Mantiene método y cuerpo sin cambios.
|
||||
|
|
@ -45,10 +47,12 @@ impl Redirect {
|
|||
/// Indicada para reorganizaciones de un sitio o aplicación web en las que también existen
|
||||
/// métodos distintos de GET (POST, PUT, ...) que no deben degradarse a GET.
|
||||
#[must_use]
|
||||
pub fn permanent(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::PermanentRedirect()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
pub fn permanent(redirect_to_url: &str) -> Response {
|
||||
(
|
||||
http::StatusCode::PERMANENT_REDIRECT,
|
||||
[(http::header::LOCATION, redirect_to_url.to_owned())],
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
/// Redirección **temporal**. Código de estado **302**. El método GET (y normalmente HEAD) se
|
||||
|
|
@ -57,10 +61,12 @@ impl Redirect {
|
|||
/// Útil cuando un recurso está fuera de servicio de forma imprevista (mantenimiento breve,
|
||||
/// sobrecarga, ...).
|
||||
#[must_use]
|
||||
pub fn found(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::Found()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
pub fn found(redirect_to_url: &str) -> Response {
|
||||
(
|
||||
http::StatusCode::FOUND,
|
||||
[(http::header::LOCATION, redirect_to_url.to_owned())],
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
/// Redirección **temporal**. Código de estado **303**. Método GET se mantiene tal cual. Los
|
||||
|
|
@ -69,10 +75,12 @@ impl Redirect {
|
|||
/// Se usa típicamente tras un POST o PUT para aplicar el patrón *Post/Redirect/Get*, permite
|
||||
/// recargar la página de resultados sin volver a ejecutar la operación.
|
||||
#[must_use]
|
||||
pub fn see_other(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::SeeOther()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
pub fn see_other(redirect_to_url: &str) -> Response {
|
||||
(
|
||||
http::StatusCode::SEE_OTHER,
|
||||
[(http::header::LOCATION, redirect_to_url.to_owned())],
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
/// Redirección **temporal**. Código de estado **307**. Conserva método y cuerpo íntegros.
|
||||
|
|
@ -80,10 +88,12 @@ impl Redirect {
|
|||
/// Preferible a [`found`](Self::found) cuando el sitio expone operaciones diferentes de GET que
|
||||
/// deben respetarse durante la redirección.
|
||||
#[must_use]
|
||||
pub fn temporary(redirect_to_url: &str) -> HttpResponse {
|
||||
HttpResponse::TemporaryRedirect()
|
||||
.append_header(("Location", redirect_to_url))
|
||||
.finish()
|
||||
pub fn temporary(redirect_to_url: &str) -> Response {
|
||||
(
|
||||
http::StatusCode::TEMPORARY_REDIRECT,
|
||||
[(http::header::LOCATION, redirect_to_url.to_owned())],
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
||||
/// Respuesta **especial**. Código de estado **304**. Se envía tras una petición condicional,
|
||||
|
|
@ -92,7 +102,7 @@ impl Redirect {
|
|||
///
|
||||
/// No es una redirección, el cliente debe reutilizar su copia local.
|
||||
#[must_use]
|
||||
pub fn not_modified() -> HttpResponse {
|
||||
HttpResponse::NotModified().finish()
|
||||
pub fn not_modified() -> Response {
|
||||
http::StatusCode::NOT_MODIFIED.into_response()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue