@@ -1678,6 +1678,138 @@ impl Default for RustApi {
16781678 }
16791679}
16801680
1681+ /// Check Basic Auth header against expected credentials
1682+ #[ cfg( feature = "swagger-ui" ) ]
1683+ fn check_basic_auth ( req : & crate :: Request , expected : & str ) -> bool {
1684+ req. headers ( )
1685+ . get ( http:: header:: AUTHORIZATION )
1686+ . and_then ( |v| v. to_str ( ) . ok ( ) )
1687+ . map ( |auth| auth == expected)
1688+ . unwrap_or ( false )
1689+ }
1690+
1691+ /// Create 401 Unauthorized response with WWW-Authenticate header
1692+ #[ cfg( feature = "swagger-ui" ) ]
1693+ fn unauthorized_response ( ) -> crate :: Response {
1694+ http:: Response :: builder ( )
1695+ . status ( http:: StatusCode :: UNAUTHORIZED )
1696+ . header (
1697+ http:: header:: WWW_AUTHENTICATE ,
1698+ "Basic realm=\" API Documentation\" " ,
1699+ )
1700+ . header ( http:: header:: CONTENT_TYPE , "text/plain" )
1701+ . body ( crate :: response:: Body :: from ( "Unauthorized" ) )
1702+ . unwrap ( )
1703+ }
1704+
1705+ /// Configuration builder for RustAPI with auto-routes
1706+ pub struct RustApiConfig {
1707+ docs_path : Option < String > ,
1708+ docs_enabled : bool ,
1709+ api_title : String ,
1710+ api_version : String ,
1711+ api_description : Option < String > ,
1712+ body_limit : Option < usize > ,
1713+ layers : LayerStack ,
1714+ }
1715+
1716+ impl Default for RustApiConfig {
1717+ fn default ( ) -> Self {
1718+ Self :: new ( )
1719+ }
1720+ }
1721+
1722+ impl RustApiConfig {
1723+ pub fn new ( ) -> Self {
1724+ Self {
1725+ docs_path : Some ( "/docs" . to_string ( ) ) ,
1726+ docs_enabled : true ,
1727+ api_title : "RustAPI" . to_string ( ) ,
1728+ api_version : "1.0.0" . to_string ( ) ,
1729+ api_description : None ,
1730+ body_limit : None ,
1731+ layers : LayerStack :: new ( ) ,
1732+ }
1733+ }
1734+
1735+ /// Set the docs path (default: "/docs")
1736+ pub fn docs_path ( mut self , path : impl Into < String > ) -> Self {
1737+ self . docs_path = Some ( path. into ( ) ) ;
1738+ self
1739+ }
1740+
1741+ /// Enable or disable docs (default: true)
1742+ pub fn docs_enabled ( mut self , enabled : bool ) -> Self {
1743+ self . docs_enabled = enabled;
1744+ self
1745+ }
1746+
1747+ /// Set OpenAPI info
1748+ pub fn openapi_info (
1749+ mut self ,
1750+ title : impl Into < String > ,
1751+ version : impl Into < String > ,
1752+ description : Option < impl Into < String > > ,
1753+ ) -> Self {
1754+ self . api_title = title. into ( ) ;
1755+ self . api_version = version. into ( ) ;
1756+ self . api_description = description. map ( |d| d. into ( ) ) ;
1757+ self
1758+ }
1759+
1760+ /// Set body size limit
1761+ pub fn body_limit ( mut self , limit : usize ) -> Self {
1762+ self . body_limit = Some ( limit) ;
1763+ self
1764+ }
1765+
1766+ /// Add a middleware layer
1767+ pub fn layer < L > ( mut self , layer : L ) -> Self
1768+ where
1769+ L : MiddlewareLayer ,
1770+ {
1771+ self . layers . push ( Box :: new ( layer) ) ;
1772+ self
1773+ }
1774+
1775+ /// Build the RustApi instance
1776+ pub fn build ( self ) -> RustApi {
1777+ let mut app = RustApi :: new ( ) . mount_auto_routes_grouped ( ) ;
1778+
1779+ // Apply configuration
1780+ if let Some ( limit) = self . body_limit {
1781+ app = app. body_limit ( limit) ;
1782+ }
1783+
1784+ app = app. openapi_info (
1785+ & self . api_title ,
1786+ & self . api_version ,
1787+ self . api_description . as_deref ( ) ,
1788+ ) ;
1789+
1790+ #[ cfg( feature = "swagger-ui" ) ]
1791+ if self . docs_enabled {
1792+ if let Some ( path) = self . docs_path {
1793+ app = app. docs ( & path) ;
1794+ }
1795+ }
1796+
1797+ // Apply layers
1798+ // Note: layers are applied in reverse order in RustApi::layer logic (pushing to vec)
1799+ app. layers . extend ( self . layers ) ;
1800+
1801+ app
1802+ }
1803+
1804+ /// Build and run the server
1805+ pub async fn run (
1806+ self ,
1807+ addr : impl AsRef < str > ,
1808+ ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
1809+ self . build ( ) . run ( addr. as_ref ( ) ) . await
1810+ }
1811+ }
1812+
16811813#[ cfg( test) ]
16821814mod tests {
16831815 use super :: RustApi ;
@@ -2462,134 +2594,3 @@ mod tests {
24622594 }
24632595}
24642596
2465- /// Check Basic Auth header against expected credentials
2466- #[ cfg( feature = "swagger-ui" ) ]
2467- fn check_basic_auth ( req : & crate :: Request , expected : & str ) -> bool {
2468- req. headers ( )
2469- . get ( http:: header:: AUTHORIZATION )
2470- . and_then ( |v| v. to_str ( ) . ok ( ) )
2471- . map ( |auth| auth == expected)
2472- . unwrap_or ( false )
2473- }
2474-
2475- /// Create 401 Unauthorized response with WWW-Authenticate header
2476- #[ cfg( feature = "swagger-ui" ) ]
2477- fn unauthorized_response ( ) -> crate :: Response {
2478- http:: Response :: builder ( )
2479- . status ( http:: StatusCode :: UNAUTHORIZED )
2480- . header (
2481- http:: header:: WWW_AUTHENTICATE ,
2482- "Basic realm=\" API Documentation\" " ,
2483- )
2484- . header ( http:: header:: CONTENT_TYPE , "text/plain" )
2485- . body ( crate :: response:: Body :: from ( "Unauthorized" ) )
2486- . unwrap ( )
2487- }
2488-
2489- /// Configuration builder for RustAPI with auto-routes
2490- pub struct RustApiConfig {
2491- docs_path : Option < String > ,
2492- docs_enabled : bool ,
2493- api_title : String ,
2494- api_version : String ,
2495- api_description : Option < String > ,
2496- body_limit : Option < usize > ,
2497- layers : LayerStack ,
2498- }
2499-
2500- impl Default for RustApiConfig {
2501- fn default ( ) -> Self {
2502- Self :: new ( )
2503- }
2504- }
2505-
2506- impl RustApiConfig {
2507- pub fn new ( ) -> Self {
2508- Self {
2509- docs_path : Some ( "/docs" . to_string ( ) ) ,
2510- docs_enabled : true ,
2511- api_title : "RustAPI" . to_string ( ) ,
2512- api_version : "1.0.0" . to_string ( ) ,
2513- api_description : None ,
2514- body_limit : None ,
2515- layers : LayerStack :: new ( ) ,
2516- }
2517- }
2518-
2519- /// Set the docs path (default: "/docs")
2520- pub fn docs_path ( mut self , path : impl Into < String > ) -> Self {
2521- self . docs_path = Some ( path. into ( ) ) ;
2522- self
2523- }
2524-
2525- /// Enable or disable docs (default: true)
2526- pub fn docs_enabled ( mut self , enabled : bool ) -> Self {
2527- self . docs_enabled = enabled;
2528- self
2529- }
2530-
2531- /// Set OpenAPI info
2532- pub fn openapi_info (
2533- mut self ,
2534- title : impl Into < String > ,
2535- version : impl Into < String > ,
2536- description : Option < impl Into < String > > ,
2537- ) -> Self {
2538- self . api_title = title. into ( ) ;
2539- self . api_version = version. into ( ) ;
2540- self . api_description = description. map ( |d| d. into ( ) ) ;
2541- self
2542- }
2543-
2544- /// Set body size limit
2545- pub fn body_limit ( mut self , limit : usize ) -> Self {
2546- self . body_limit = Some ( limit) ;
2547- self
2548- }
2549-
2550- /// Add a middleware layer
2551- pub fn layer < L > ( mut self , layer : L ) -> Self
2552- where
2553- L : MiddlewareLayer ,
2554- {
2555- self . layers . push ( Box :: new ( layer) ) ;
2556- self
2557- }
2558-
2559- /// Build the RustApi instance
2560- pub fn build ( self ) -> RustApi {
2561- let mut app = RustApi :: new ( ) . mount_auto_routes_grouped ( ) ;
2562-
2563- // Apply configuration
2564- if let Some ( limit) = self . body_limit {
2565- app = app. body_limit ( limit) ;
2566- }
2567-
2568- app = app. openapi_info (
2569- & self . api_title ,
2570- & self . api_version ,
2571- self . api_description . as_deref ( ) ,
2572- ) ;
2573-
2574- #[ cfg( feature = "swagger-ui" ) ]
2575- if self . docs_enabled {
2576- if let Some ( path) = self . docs_path {
2577- app = app. docs ( & path) ;
2578- }
2579- }
2580-
2581- // Apply layers
2582- // Note: layers are applied in reverse order in RustApi::layer logic (pushing to vec)
2583- app. layers . extend ( self . layers ) ;
2584-
2585- app
2586- }
2587-
2588- /// Build and run the server
2589- pub async fn run (
2590- self ,
2591- addr : impl AsRef < str > ,
2592- ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
2593- self . build ( ) . run ( addr. as_ref ( ) ) . await
2594- }
2595- }
0 commit comments