diff --git a/src/app.rs b/src/app.rs index 1e70860..c02ec4d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -6,6 +6,37 @@ use tokio::{net::TcpListener, sync::Mutex}; use crate::{handler::Handler, router::Router, Error, ServerError}; +/// App is used to define application-level functionality and initialize the server. Routes are +/// typically programmed here. +/// +/// ```ignore +/// async fn item( +/// req: Request, +/// resp: Option>, +/// params: Params, +/// app: App<()> +/// ) -> HTTPResult { +/// Ok(( +/// req, +/// Response::builder(). +/// status(StatusCode::OK). +/// body(Body::default()). +/// unwrap() +/// )) +/// } +/// +/// #[tokio::main] +/// async fn main() -> Result<(), ServerError> { +/// let app = App::new(); +/// app.get("/:item", compose_handler!(item)); +/// app.serve("localhost:0").await +/// } +/// ``` +/// +/// Note that App here has _no state_. It will have a type signature of `App<()>`. To carry state, +/// look at the `with_state` method which will change the type signature of the `item` call (and +/// other handlers). +/// #[derive(Clone)] pub struct App { router: Router, @@ -13,6 +44,7 @@ pub struct App { } impl App { + /// Construct a new App with no state; it will be passed to handlers as `App<()>`. pub fn new() -> Self { Self { router: Router::new(), @@ -20,6 +52,11 @@ impl App { } } + /// Construct an App with state. + /// + /// This has the type `App` where S is `+ 'static + Clone + Send` and will be passed to + /// handlers with the appropriate concrete type. + /// pub fn with_state(state: S) -> Self { Self { router: Router::new(), @@ -27,46 +64,70 @@ impl App { } } + // FIXME Currently you must await this, seems pointless. + /// Return the state of the App. This is returned as `Arc>` and must be acquired under + /// lock. In situations where there is no state, [std::option::Option::None] is returned. pub async fn state(&self) -> Option>> { self.global_state.clone() } + /// Create a route for a GET request. See [crate::path::Path] and [crate::handler::Handler] for + /// more information. pub fn get(&mut self, path: &str, ch: Handler) { self.router.add(Method::GET, path.to_string(), ch); } + /// Create a route for a POST request. See [crate::path::Path] and [crate::handler::Handler] for + /// more information. pub fn post(&mut self, path: &str, ch: Handler) { self.router.add(Method::POST, path.to_string(), ch); } + /// Create a route for a DELETE request. See [crate::path::Path] and [crate::handler::Handler] for + /// more information. pub fn delete(&mut self, path: &str, ch: Handler) { self.router.add(Method::DELETE, path.to_string(), ch); } + /// Create a route for a PUT request. See [crate::path::Path] and [crate::handler::Handler] for + /// more information. pub fn put(&mut self, path: &str, ch: Handler) { self.router.add(Method::PUT, path.to_string(), ch); } + /// Create a route for an OPTIONS request. See [crate::path::Path] and + /// [crate::handler::Handler] for more information. pub fn options(&mut self, path: &str, ch: Handler) { self.router.add(Method::OPTIONS, path.to_string(), ch); } + /// Create a route for a PATCH request. See [crate::path::Path] and + /// [crate::handler::Handler] for more information. pub fn patch(&mut self, path: &str, ch: Handler) { self.router.add(Method::PATCH, path.to_string(), ch); } + /// Create a route for a HEAD request. See [crate::path::Path] and + /// [crate::handler::Handler] for more information. pub fn head(&mut self, path: &str, ch: Handler) { self.router.add(Method::HEAD, path.to_string(), ch); } + /// Create a route for a CONNECT request. See [crate::path::Path] and + /// [crate::handler::Handler] for more information. pub fn connect(&mut self, path: &str, ch: Handler) { self.router.add(Method::CONNECT, path.to_string(), ch); } + /// Create a route for a TRACE request. See [crate::path::Path] and + /// [crate::handler::Handler] for more information. pub fn trace(&mut self, path: &str, ch: Handler) { self.router.add(Method::TRACE, path.to_string(), ch); } + /// Dispatch a route based on the request. Returns a response based on the error status of the + /// handler chain following the normal chain of responsibility rules described elsewhere. Only + /// needed by server implementors. pub async fn dispatch(&self, req: Request) -> Result, Infallible> { match self.router.dispatch(req, self.clone()).await { Ok(resp) => Ok(resp), @@ -83,6 +144,8 @@ impl App { } } + /// Start a TCP/HTTP server with tokio. Performs dispatch on an as-needed basis. This is a more + /// common path for users to start a server. pub async fn serve(self, addr: &str) -> Result<(), ServerError> { let socketaddr: SocketAddr = addr.parse()?; diff --git a/src/lib.rs b/src/lib.rs index 9386d0b..c7d2c34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,12 @@ +/// Application/Server-level management and routing configuration; outermost functionality. pub mod app; +/// Handler construction and prototypes pub mod handler; +/// Macros for quality-of-life when interacting with Handlers pub mod macros; +/// Path management for Routes pub mod path; +/// Router, Route management and organization pub mod router; use http::{Request, Response}; @@ -9,6 +14,7 @@ use std::pin::Pin; pub(crate) type PinBox = Pin>; +/// An error for server-related issues. #[derive(Debug, Clone)] pub struct ServerError(String); @@ -21,6 +27,9 @@ where } } +/// General errors for ratpack handlers. Yield either a StatusCode for a literal status, or a +/// String for a 500 Internal Server Error. Other status codes should be yielded through +/// [http::Response] returns. #[derive(Clone, Debug)] pub enum Error { StatusCode(http::StatusCode), @@ -34,6 +43,7 @@ impl Default for Error { } impl Error { + /// Convenience method to pass anything in that accepts a .to_string method. pub fn new(message: T) -> Self where T: ToString, @@ -41,6 +51,7 @@ impl Error { Self::InternalServerError(message.to_string()) } + /// A convenient way to return status codes. pub fn new_status(error: http::StatusCode) -> Self { Self::StatusCode(error) } @@ -55,4 +66,7 @@ where } } +/// HTTPResult is the return type for handlers. If a handler terminates at the end of its chain +/// with [std::option::Option::None] as the [http::Response], a 500 Internal Server Error will be +/// returned. pub type HTTPResult = Result<(Request, Option>), Error>; diff --git a/src/macros.rs b/src/macros.rs index c77f13a..c1f1299 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,3 +1,9 @@ +/// compose_handler allows you to combine [crate::handler::HandlerFunc] functions into a single [crate::handler::Handler], so that +/// they cascade through a chain of responsibility. This means that each handler will feed its +/// output into the input of the next. To start, the first [http::Response] is +/// [std::option::Option::None], and the final return Response must be non-None otherwise a 500 +/// Internal Server Error is returned. Handlers may do anything they wish to the [http::Request] between +/// processing periods, including replacing the request entirely. #[macro_export] macro_rules! compose_handler { ($( $x:path ),*) => {