66import os
77import requests
88import logging
9- from urllib .parse import quote , unquote
109from starlette .responses import RedirectResponse
1110from authlib .integrations .starlette_client import OAuth
1211from starlette .config import Config
@@ -64,29 +63,29 @@ def require_login(request: Request):
6463 request .session ['user' ] = "anonymous"
6564 return request .session ['user' ]
6665
67-
68- @ app . get ( "/proxy" , include_in_schema = False )
69- async def proxy ( url : str , headers : str = None , user = Depends ( require_login )) :
70- """
71- Proxy endpoint to fetch the OpenAPI document from a given URL (JSON or YAML).
72- """
73- try :
74- if headers :
75- resp = requests . get ( url , headers = json . loads ( unquote ( headers )), timeout = int ( os . environ . get ( "PROXY_TIMEOUT" , 10 )))
76- else :
77- resp = requests . get ( url , timeout = int ( os . environ . get ( "PROXY_TIMEOUT" , 10 )) )
78- content_type = resp . headers . get ( "content-type" , " " )
79- # Se for JSON, repasse como application/json
80- if "json" in content_type :
81- return Response ( content = resp . content , media_type = " application/json" )
82- # Se for YAML, repasse como text/yaml
83- elif "yaml" in content_type or "yml" in content_type :
84- return Response ( content = resp . content , media_type = " text/yaml" )
85- else :
86- raise HTTPException ( status_code = 400 , detail = "Unsupported content type " )
87- except requests . RequestException as e :
88- logger .error (f"Error fetching OpenAPI document : { e } " )
89- raise HTTPException (status_code = 500 , detail = { "error" : "Failed to fetch OpenAPI document" , "details" : str ( e )} )
66+ @ app . get ( "/services/{name}" , response_class = HTMLResponse , include_in_schema = False )
67+ async def services ( request : Request , name : str , user = Depends ( require_login )):
68+ with open ( 'static/openapi/services.json' , 'r' ) as f :
69+ services = json . load ( f )
70+ logger . info ( f"Loaded { len ( services ) } services." )
71+ if name not in services :
72+ logger . error ( f"Service { name } not found." )
73+ raise HTTPException ( status_code = 404 , detail = "Service not found" )
74+ service = services [ name ]
75+ if not service :
76+ logger . error ( f"Service { name } not found." )
77+ raise HTTPException ( status_code = 404 , detail = "Service not found " )
78+ resp = requests . get ( service [ 'url' ], timeout = int ( os . environ . get ( "PROXY_TIMEOUT" , 10 )), headers = parse_headers ( service . get ( "header" )))
79+ content_type = resp . headers . get ( "content-type" , "" )
80+ # Se for JSON, repasse como application/json
81+ if "json" in content_type :
82+ return Response ( content = resp . content , media_type = "application/json" )
83+ # Se for YAML, repasse como text/yaml
84+ elif "yaml" in content_type or "yml" in content_type :
85+ return Response ( content = resp . content , media_type = "text/yaml " )
86+ else :
87+ logger .error (f"Unsupported content type : { content_type } " )
88+ raise HTTPException (status_code = 400 , detail = "Unsupported content type" )
9089
9190def parse_headers (header_string : str ) -> dict :
9291 headers = {}
@@ -100,81 +99,59 @@ def parse_headers(header_string: str) -> dict:
10099 return headers
101100
102101
103- def apply_proxy_to_openapi (openapi_url : str , header : str = None ) -> str :
104- """
105- Apply the proxy to the OpenAPI URL.
106- """
107- if openapi_url .startswith ("http" ):
108- new_url = f"/proxy?url={ openapi_url } "
109- if header :
110- header = quote (json .dumps (header ))
111- new_url += f"&headers={ header } "
112- return new_url
113- return openapi_url
114-
115-
116102@app .get ("/" , response_class = HTMLResponse )
117- async def docs (request : Request , template :str = None , user = Depends (require_login )):
118- """
119- Main documentation page.
120- """
103+ async def index (request : Request , template :str = 'swagger-ui' , user = Depends (require_login )):
104+ if template . lower () not in [ "redoc" , "swagger-ui" ]:
105+ raise HTTPException ( status_code = 400 , detail = "Invalid template. Use 'redoc' or 'swagger-ui'." )
106+
121107 try :
122- with open ('static/openapi/urls.json' , 'r' ) as f :
123- swaggers = json .load (f )
124- logger .info (f"Loaded { len (swaggers )} URLs." )
125- except FileNotFoundError :
126- logger .error ("File not found: static/openapi/urls.json" )
127- request .session ['error' ] = "File not found: static/openapi/urls.json"
128- swaggers = [
129- {
130- "url" : "/openapi.json" ,
131- "name" : "Swagger Aggregator" ,
132- "header" : "" ,
133- }
134- ]
135- except json .JSONDecodeError :
136- logger .error ("Error decoding JSON from static/openapi/urls.json" )
137- request .session ['error' ] = "Error decoding JSON from static/openapi/urls.json"
138- swaggers = [
139- {
140- "url" : "/openapi.json" ,
141- "name" : "Swagger Aggregator" ,
142- "header" : "" ,
143- }
144- ]
145-
146- for swagger in swaggers :
147- swagger ["url" ] = apply_proxy_to_openapi (swagger .get ("url" ), parse_headers (swagger .get ("header" )))
148-
149- if template and template .lower () in ["redoc" , "swagger-ui" ]:
150- return templates .TemplateResponse (
151- f"{ template .lower ()} .html" ,
152- {
153- "request" : request ,
154- "urls" : swaggers ,
155- "title" : os .environ .get ("TITLE" , "API Documentation" ),
156- }
157- )
158- interface = os .environ .get ("INTERFACE" , "swagger-ui" ).lower ()
159- if interface not in ["swagger-ui" , "redoc" ]:
160- interface = "swagger-ui"
161- return templates .TemplateResponse (
162- f"{ interface } .html" ,
163- {
164- "request" : request ,
165- "urls" : swaggers ,
166- "title" : os .environ .get ("TITLE" , "API Documentation" ),
167- }
168- )
108+ with open ('static/openapi/services.json' , 'r' ) as f :
109+ services = json .load (f )
110+ logger .info (f"Loaded { len (services )} services." )
111+ except Exception as e :
112+ logger .error (f"Error loading services file: { e } " )
113+ raise HTTPException (status_code = 500 , detail = "Error loading services file." )
114+
115+ urls = []
116+ for service_name , service in services .items ():
117+ urls .append ({
118+ "url" : f"/services/{ service_name } " ,
119+ "name" : service ['name' ],
120+ "header" : service .get ("header" , "" ),
121+ })
122+
123+ match template .lower ():
124+ case "redoc" :
125+ return templates .TemplateResponse (
126+ "redoc.html" ,
127+ {
128+ "request" : request ,
129+ "urls" : urls ,
130+ "title" : os .environ .get ("TITLE" , "API Documentation" ),
131+ }
132+ )
133+ case "swagger-ui" :
134+ return templates .TemplateResponse (
135+ "swagger-ui.html" ,
136+ {
137+ "request" : request ,
138+ "urls" : urls ,
139+ "title" : os .environ .get ("TITLE" , "API Documentation" ),
140+ }
141+ )
142+ case _:
143+ logger .error (f"Invalid template: { template } " )
144+ raise HTTPException (status_code = 400 , detail = "Invalid template. Use 'redoc' or 'swagger-ui'." )
145+
169146
170147@app .get ("/config" , response_class = HTMLResponse , include_in_schema = False )
171148async def config (request : Request , user = Depends (require_login )):
172149 """
173150 Configuration page for the OpenAPI URLs.
174151 """
175152 try :
176- with open ('static/openapi/urls .json' ) as f :
177- swaggers = json .load (f )
153+ with open ('static/openapi/services .json' ) as f :
154+ swaggers = json .load (f ). values ()
178155 except Exception as e :
179156 logger .error (f"Error loading configuration file: { e } " )
180157 swaggers = []
0 commit comments