http_kit/
endpoint.rs

1//! HTTP endpoint abstraction for request handling.
2//!
3//! This module provides the core [`Endpoint`] trait and supporting types for building
4//! HTTP request handlers. Endpoints represent the final destination for HTTP requests
5//! and are responsible for generating appropriate responses.
6//!
7//! # Core Concepts
8//!
9//! - **Endpoint**: A trait for types that can handle HTTP requests and produce responses
10//! - **Middleware Integration**: Endpoints can be combined with middleware for cross-cutting concerns
11//! - **Type Erasure**: Support for dynamic dispatch through [`AnyEndpoint`]
12//! - **Composition**: Endpoints can be wrapped and combined in various ways
13//!
14//! # Examples
15//!
16//! ## Basic Endpoint Implementation
17//!
18//! ```rust
19//! use http_kit::{Request, Response, Endpoint, Body};
20//! use core::convert::Infallible;
21//!
22//! struct HelloEndpoint;
23//!
24//! impl Endpoint for HelloEndpoint {
25//!     type Error = Infallible;
26//!     async fn respond(&mut self, _request: &mut Request) -> Result<Response, Self::Error> {
27//!         Ok(Response::new(Body::from_bytes("Hello, World!")))
28//!     }
29//! }
30//! ```
31//!
32//! ## Endpoint with Request Processing
33//!
34//! ```rust
35//! use http_kit::{Request, Response, Result, Endpoint, Body, Error};
36//!
37//! struct EchoEndpoint;
38//!
39//! impl Endpoint for EchoEndpoint {
40//!     type Error = Error;
41//!     async fn respond(&mut self, request: &mut Request) -> Result<Response> {
42//!         let body = std::mem::replace(request.body_mut(), Body::empty());
43//!         Ok(Response::new(body))
44//!     }
45//! }
46//! ```
47//!
48//! ## Using with Middleware
49//!
50//! ```rust
51//! use http_kit::{Request, Response, Result, Endpoint, Middleware, endpoint::WithMiddleware, Body, Error};
52//! use http_kit::middleware::MiddlewareError;
53//!
54//! struct LoggingMiddleware;
55//!
56//! impl Middleware for LoggingMiddleware {
57//!     type Error = Error;
58//!     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
59//!         println!("Processing request to {}", request.uri());
60//!         next.respond(request).await.map_err(MiddlewareError::Endpoint)
61//!     }
62//! }
63//!
64//! struct MyEndpoint;
65//! impl Endpoint for MyEndpoint {
66//!     type Error = Error;
67//!     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
68//!         Ok(Response::new(Body::from_bytes("OK")))
69//!     }
70//! }
71//!
72//! let endpoint_with_logging = WithMiddleware::new(MyEndpoint, LoggingMiddleware);
73//! ```
74
75use core::{any::type_name, fmt::Debug, future::Future, ops::DerefMut, pin::Pin};
76
77use alloc::boxed::Box;
78
79use crate::{
80    error::BoxHttpError, middleware::MiddlewareError, HttpError, Middleware, Request, Response,
81};
82
83/// A trait for types that can handle HTTP requests and generate responses.
84///
85/// Endpoints represent the final destination in the HTTP request processing pipeline.
86/// They receive a mutable reference to the request (allowing them to consume the body
87/// or modify headers) and return a response or error.
88///
89/// # Implementation Notes
90///
91/// - Endpoints must be `Send` to work in async contexts
92/// - The request parameter is mutable, allowing body consumption and header modification
93/// - Implementations should handle errors gracefully and return appropriate HTTP status codes
94/// - Endpoints can be combined with middleware for additional functionality
95///
96/// # Examples
97///
98/// ## Simple Text Response
99///
100/// ```rust
101/// use http_kit::{Request, Response, Result, Endpoint, Body, Error};
102///
103/// struct GreetingEndpoint {
104///     name: String,
105/// }
106///
107/// impl Endpoint for GreetingEndpoint {
108///     type Error = Error;
109///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
110///         let message = format!("Hello, {}!", self.name);
111///         Ok(Response::new(Body::from_bytes(message)))
112///     }
113/// }
114/// ```
115///
116/// ## JSON API Endpoint
117///
118/// ```rust
119/// # #[cfg(feature = "json")]
120/// # {
121/// use http::StatusCode;
122/// use http_kit::{Request, Response, Result, Endpoint, Body, HttpError, BodyError};
123/// use serde::{Serialize, Deserialize};
124/// use thiserror::Error;
125///
126/// #[derive(Debug, Error)]
127/// enum ApiError {
128///     #[error("json error: {0}")]
129///     Json(#[from] serde_json::Error),
130///     #[error("body error: {0}")]
131///     Body(#[from] BodyError),
132/// }
133///
134/// impl HttpError for ApiError {
135///     fn status(&self) -> Option<StatusCode> {
136///         match self {
137///             Self::Json(_) => Some(StatusCode::BAD_REQUEST),
138///             Self::Body(_) => Some(StatusCode::INTERNAL_SERVER_ERROR),
139///         }
140///     }
141/// }
142///
143/// #[derive(Serialize, Deserialize)]
144/// struct User { name: String, age: u32 }
145///
146/// struct UserEndpoint;
147///
148/// impl Endpoint for UserEndpoint {
149///     type Error = ApiError;
150///     async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
151///         match request.method().as_str() {
152///             "GET" => {
153///                 let user = User { name: "Alice".into(), age: 30 };
154///                 let body = Body::from_json(&user)?;
155///                 Ok(Response::new(body))
156///             }
157///             "POST" => {
158///                 let user: User = request
159///                     .body_mut()
160///                     .into_json()
161///                     .await?;
162///                 // Process user...
163///                 let body = Body::from_json(&user)?;
164///                 Ok(Response::new(body))
165///             }
166///             _ => Ok(Response::new(Body::from_bytes("Method Not Allowed")))
167///         }
168///     }
169/// }
170/// # }
171/// ```
172pub trait Endpoint: Send {
173    /// The error type returned by this endpoint.
174    type Error: HttpError;
175    /// Processes an HTTP request and generates a response.
176    ///
177    /// This method receives a mutable reference to the request, allowing it to:
178    /// - Consume the request body with `take_body()` or similar methods
179    /// - Read headers, URI, method, and other request metadata
180    /// - Modify request state if needed (though this is less common)
181    ///
182    /// The method should return either a successful `Response` or an `Error`
183    /// with an appropriate HTTP status code.
184    ///
185    /// # Arguments
186    ///
187    /// * `request` - Mutable reference to the HTTP request being processed
188    ///
189    /// # Examples
190    ///
191    /// ```rust
192    /// use http_kit::{Request, Response, Result, Endpoint, Body, Error};
193    ///
194    /// struct StatusEndpoint;
195    ///
196    /// impl Endpoint for StatusEndpoint {
197    ///     type Error = Error;
198    ///     async fn respond(&mut self, request: &mut Request) -> Result<Response> {
199    ///         let status = format!("Method: {}, URI: {}", request.method(), request.uri());
200    ///         Ok(Response::new(Body::from_bytes(status)))
201    ///     }
202    /// }
203    /// ```
204    fn respond(
205        &mut self,
206        request: &mut Request,
207    ) -> impl Future<Output = Result<Response, Self::Error>> + Send;
208}
209
210impl<E: Endpoint> Endpoint for &mut E {
211    type Error = E::Error;
212    async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
213        Endpoint::respond(*self, request).await
214    }
215}
216
217impl<E: Endpoint> Endpoint for Box<E> {
218    type Error = E::Error;
219    async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
220        Endpoint::respond(self.deref_mut(), request).await
221    }
222}
223
224/// A wrapper that combines an endpoint with middleware.
225///
226/// `WithMiddleware` allows you to compose an endpoint with middleware to add
227/// cross-cutting concerns like logging, authentication, rate limiting, etc.
228/// The middleware is executed first and can decide whether to call the endpoint
229/// and how to process the response.
230///
231/// # Type Parameters
232///
233/// * `E` - The endpoint type that implements `Endpoint`
234/// * `M` - The middleware type that implements `Middleware`
235///
236/// # Examples
237///
238/// ```rust
239/// use http_kit::{Request, Response, Result, Endpoint, Middleware, endpoint::WithMiddleware, Body, Error};
240/// use http_kit::middleware::MiddlewareError;
241///
242/// struct TimingMiddleware;
243/// impl Middleware for TimingMiddleware {
244///     type Error = Error;
245///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
246///         let start = std::time::Instant::now();
247///         let response = next.respond(request).await;
248///         let duration = start.elapsed();
249///         println!("Request took {:?}", duration);
250///         response.map_err(MiddlewareError::Endpoint)
251///     }
252/// }
253///
254/// struct HelloEndpoint;
255/// impl Endpoint for HelloEndpoint {
256///     type Error = Error;
257///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
258///         Ok(Response::new(Body::from_bytes("Hello")))
259///     }
260/// }
261///
262/// let timed_endpoint = WithMiddleware::new(HelloEndpoint, TimingMiddleware);
263/// ```
264#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
265pub struct WithMiddleware<E: Endpoint, M: Middleware> {
266    endpoint: E,
267    middleware: M,
268}
269
270impl<E: Endpoint, M: Middleware> WithMiddleware<E, M> {
271    /// Creates a new endpoint that wraps the given endpoint with middleware.
272    ///
273    /// When the resulting endpoint handles a request, the middleware will be
274    /// executed first. The middleware can then decide whether to call the
275    /// wrapped endpoint and how to process its response.
276    ///
277    /// # Arguments
278    ///
279    /// * `endpoint` - The endpoint to wrap
280    /// * `middleware` - The middleware to apply
281    ///
282    /// # Examples
283    ///
284    /// ```rust
285    /// use http_kit::{Request, Response, Result, Endpoint, Middleware, endpoint::WithMiddleware, Body, Error};
286    /// use http_kit::middleware::MiddlewareError;
287    ///
288    /// struct AuthMiddleware { token: String }
289    /// impl Middleware for AuthMiddleware {
290    ///     type Error = Error;
291    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
292    ///         if let Some(auth) = request.headers().get(http::header::AUTHORIZATION) {
293    ///             if auth.as_bytes() == self.token.as_bytes() {
294    ///                 return next.respond(request).await.map_err(MiddlewareError::Endpoint);
295    ///             }
296    ///         }
297    ///         Ok(Response::new(Body::from_bytes("Unauthorized")))
298    ///     }
299    /// }
300    ///
301    /// struct SecretEndpoint;
302    /// impl Endpoint for SecretEndpoint {
303    ///     type Error = Error;
304    ///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
305    ///         Ok(Response::new(Body::from_bytes("Secret data")))
306    ///     }
307    /// }
308    ///
309    /// let auth_middleware = AuthMiddleware { token: "secret".to_string() };
310    /// let protected_endpoint = WithMiddleware::new(SecretEndpoint, auth_middleware);
311    /// ```
312    pub fn new(endpoint: E, middleware: M) -> Self {
313        Self {
314            endpoint,
315            middleware,
316        }
317    }
318}
319
320impl<E: Endpoint, M: Middleware> Endpoint for WithMiddleware<E, M> {
321    type Error = MiddlewareError<E::Error, M::Error>;
322    async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
323        self.middleware.handle(request, &mut self.endpoint).await
324    }
325}
326
327pub(crate) trait EndpointImpl: Send {
328    fn respond_inner<'this, 'req, 'fut>(
329        &'this mut self,
330        request: &'req mut Request,
331    ) -> Pin<Box<dyn 'fut + Send + Future<Output = Result<Response, BoxHttpError>>>>
332    where
333        'this: 'fut,
334        'req: 'fut;
335    fn name(&self) -> &'static str {
336        type_name::<Self>()
337    }
338}
339
340/// Type-erased endpoint that can hold any endpoint implementation behind a trait object.
341///
342/// `AnyEndpoint` provides dynamic dispatch for endpoints, allowing you to store
343/// different endpoint types in the same collection or pass them around without
344/// knowing their concrete types at compile time. This is useful for building
345/// flexible routing systems or plugin architectures.
346///
347/// # Performance Notes
348///
349/// Using `AnyEndpoint` involves dynamic dispatch and heap allocation, which has
350/// a small performance overhead compared to using concrete types directly.
351/// However, this is often negligible in HTTP server contexts.
352///
353/// # Examples
354///
355/// ```rust
356/// use http_kit::{Request, Response, Result, Endpoint, endpoint::AnyEndpoint, Body, Error};
357///
358/// struct HelloEndpoint;
359/// impl Endpoint for HelloEndpoint {
360///     type Error = Error;
361///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
362///         Ok(Response::new(Body::from_bytes("Hello")))
363///     }
364/// }
365///
366/// struct GoodbyeEndpoint;
367/// impl Endpoint for GoodbyeEndpoint {
368///     type Error = Error;
369///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
370///         Ok(Response::new(Body::from_bytes("Goodbye")))
371///     }
372/// }
373///
374/// // Store different endpoint types in a collection
375/// let endpoints: Vec<AnyEndpoint> = vec![
376///     AnyEndpoint::new(HelloEndpoint),
377///     AnyEndpoint::new(GoodbyeEndpoint),
378/// ];
379/// ```
380pub struct AnyEndpoint(Box<dyn EndpointImpl>);
381
382impl Debug for AnyEndpoint {
383    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
384        f.write_fmt(format_args!("AnyEndpoint[{}]", self.name()))
385    }
386}
387
388impl AnyEndpoint {
389    /// Creates a new type-erased endpoint wrapper around the given endpoint implementation.
390    ///
391    /// This method takes any type that implements `Endpoint` and wraps it in a
392    /// `AnyEndpoint` that can be stored alongside other endpoints of different types.
393    ///
394    /// # Arguments
395    ///
396    /// * `endpoint` - Any endpoint implementation
397    ///
398    /// # Examples
399    ///
400    /// ```rust
401    /// use http_kit::{Request, Response, Result, Endpoint, endpoint::AnyEndpoint, Body, Error};
402    ///
403    /// struct MyEndpoint {
404    ///     message: String,
405    /// }
406    ///
407    /// impl Endpoint for MyEndpoint {
408    ///     type Error = Error;
409    ///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
410    ///         Ok(Response::new(Body::from_bytes(self.message.clone())))
411    ///     }
412    /// }
413    ///
414    /// let endpoint = MyEndpoint { message: "Hello!".to_string() };
415    /// let any_endpoint = AnyEndpoint::new(endpoint);
416    /// ```
417    pub fn new(endpoint: impl Endpoint + 'static) -> Self {
418        Self(Box::new(endpoint))
419    }
420
421    /// Returns the type name of the underlying endpoint implementation.
422    ///
423    /// This can be useful for debugging, logging, or introspection purposes.
424    ///
425    /// # Examples
426    ///
427    /// ```rust
428    /// use http_kit::{Request, Response, Result, Endpoint, endpoint::AnyEndpoint, Body, Error};
429    ///
430    /// struct MyEndpoint;
431    /// impl Endpoint for MyEndpoint {
432    ///     type Error = Error;
433    ///     async fn respond(&mut self, _request: &mut Request) -> Result<Response> {
434    ///         Ok(Response::new(Body::from_bytes("OK")))
435    ///     }
436    /// }
437    ///
438    /// let any_endpoint = AnyEndpoint::new(MyEndpoint);
439    /// println!("Endpoint type: {}", any_endpoint.name());
440    /// ```
441    pub fn name(&self) -> &'static str {
442        self.0.name()
443    }
444}
445
446impl<E: Endpoint> EndpointImpl for E {
447    fn respond_inner<'this, 'req, 'fut>(
448        &'this mut self,
449        request: &'req mut Request,
450    ) -> Pin<Box<dyn 'fut + Send + Future<Output = Result<Response, BoxHttpError>>>>
451    where
452        'this: 'fut,
453        'req: 'fut,
454    {
455        Box::pin(async move {
456            Endpoint::respond(self, request)
457                .await
458                .map_err(|e| Box::new(e) as BoxHttpError)
459        })
460    }
461}
462
463impl Endpoint for AnyEndpoint {
464    type Error = BoxHttpError;
465    /// Processes an HTTP request using the underlying endpoint implementation.
466    async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
467        self.0.respond_inner(request).await
468    }
469}