1+ //! Example demonstrating Extension<T> usage with OpenAPI generation
2+
3+ use gotcha:: {
4+ api, async_trait, ConfigWrapper , Extension , GotchaApp , GotchaContext , GotchaRouter , Json ,
5+ Responder , Schematic , State
6+ } ;
7+ use serde:: { Deserialize , Serialize } ;
8+
9+ #[ derive( Clone ) ]
10+ pub struct AuthContext {
11+ pub user_id : String ,
12+ pub role : String ,
13+ }
14+
15+ #[ derive( Debug , Deserialize , Serialize , Clone , Default ) ]
16+ pub struct Config {
17+ pub app_name : String ,
18+ }
19+
20+ #[ derive( Debug , Serialize , Deserialize , Schematic ) ]
21+ pub struct UserResponse {
22+ pub id : String ,
23+ pub name : String ,
24+ pub role : String ,
25+ }
26+
27+ /// Get current user information
28+ #[ api( id = "get_current_user" , group = "users" ) ]
29+ pub async fn get_current_user (
30+ Extension ( auth) : Extension < AuthContext > ,
31+ State ( _config) : State < ConfigWrapper < Config > > ,
32+ ) -> Json < UserResponse > {
33+ Json ( UserResponse {
34+ id : auth. user_id . clone ( ) ,
35+ name : format ! ( "User {}" , auth. user_id) ,
36+ role : auth. role ,
37+ } )
38+ }
39+
40+ #[ derive( Debug , Serialize , Deserialize , Schematic ) ]
41+ pub struct CreatePostRequest {
42+ pub title : String ,
43+ pub content : String ,
44+ }
45+
46+ #[ derive( Debug , Serialize , Deserialize , Schematic ) ]
47+ pub struct PostResponse {
48+ pub id : String ,
49+ pub title : String ,
50+ pub content : String ,
51+ pub author_id : String ,
52+ }
53+
54+ /// Create a new post
55+ #[ api( id = "create_post" , group = "posts" ) ]
56+ pub async fn create_post (
57+ Extension ( auth) : Extension < AuthContext > ,
58+ Json ( request) : Json < CreatePostRequest > ,
59+ ) -> Json < PostResponse > {
60+ Json ( PostResponse {
61+ id : uuid:: Uuid :: new_v4 ( ) . to_string ( ) ,
62+ title : request. title ,
63+ content : request. content ,
64+ author_id : auth. user_id ,
65+ } )
66+ }
67+
68+ /// Health check endpoint without auth
69+ #[ api( id = "health" , group = "system" ) ]
70+ pub async fn health ( ) -> Json < serde_json:: Value > {
71+ Json ( serde_json:: json!( { "status" : "healthy" } ) )
72+ }
73+
74+ pub struct App { }
75+
76+ #[ async_trait]
77+ impl GotchaApp for App {
78+ type State = ( ) ;
79+ type Config = Config ;
80+
81+ fn routes ( & self , router : GotchaRouter < GotchaContext < Self :: State , Self :: Config > > ) -> GotchaRouter < GotchaContext < Self :: State , Self :: Config > > {
82+ router
83+ . get ( "/health" , health)
84+ . get ( "/user/me" , get_current_user)
85+ . post ( "/posts" , create_post)
86+ // Add middleware to inject the AuthContext
87+ . layer ( axum:: middleware:: from_fn ( inject_auth_context) )
88+ }
89+
90+ fn state ( & self , _config : & ConfigWrapper < Self :: Config > ) -> impl std:: future:: Future < Output = Result < Self :: State , Box < dyn std:: error:: Error > > > + Send {
91+ async { Ok ( ( ) ) }
92+ }
93+ }
94+
95+ // Middleware to inject AuthContext into requests
96+ async fn inject_auth_context (
97+ mut req : axum:: extract:: Request ,
98+ next : axum:: middleware:: Next ,
99+ ) -> impl Responder {
100+ // In a real application, you would extract this from a JWT token or session
101+ let auth_context = AuthContext {
102+ user_id : "user123" . to_string ( ) ,
103+ role : "admin" . to_string ( ) ,
104+ } ;
105+
106+ req. extensions_mut ( ) . insert ( auth_context) ;
107+ next. run ( req) . await
108+ }
109+
110+ #[ tokio:: main]
111+ async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
112+ println ! ( "Starting Extension OpenAPI example server..." ) ;
113+ println ! ( "Visit http://localhost:3000/scalar for API documentation" ) ;
114+ println ! ( "Visit http://localhost:3000/openapi.json for OpenAPI spec" ) ;
115+ println ! ( ) ;
116+ println ! ( "Available endpoints:" ) ;
117+ println ! ( " GET /health - Health check (no auth)" ) ;
118+ println ! ( " GET /user/me - Get current user (uses Extension)" ) ;
119+ println ! ( " POST /posts - Create post (uses Extension)" ) ;
120+
121+ App { } . run ( ) . await ?;
122+ Ok ( ( ) )
123+ }
0 commit comments