11# app_flask.py
22import os
3- from flask import Flask , jsonify , request
3+ from flask import Flask , jsonify , request , Blueprint
44from flask_cors import CORS
55from flask_restx import Api , Resource , fields
66
7+ # Initialize Flask application
78app = Flask (__name__ )
9+
810# Enable CORS for all routes with explicit origins
911CORS (app , resources = {r"/*" : {"origins" : "*" }}, supports_credentials = True )
1012
11- # Setup Flask-RESTx
13+ # Get environment or use default
14+ env = os .environ .get ("FLASK_ENV" , "development" )
15+
16+ # Create a Blueprint for direct routes that bypass Flask-RESTX
17+ direct_routes = Blueprint ('direct_routes' , __name__ )
18+
19+ # Add root route to the Blueprint
20+ @direct_routes .route ('/' )
21+ def direct_root ():
22+ """Direct root endpoint that bypasses Flask-RESTX"""
23+ return jsonify ({
24+ "message" : "Hello from Flask!" ,
25+ "service" : "Flask API" ,
26+ "environment" : env ,
27+ "version" : "1.0.0" ,
28+ })
29+
30+ # Register the Blueprint BEFORE setting up Flask-RESTX
31+ app .register_blueprint (direct_routes )
32+
33+ # Add a plain route for ping outside of RESTx and Blueprint
34+ @app .route ('/ping' )
35+ def ping ():
36+ """Simple ping endpoint for health checks"""
37+ return jsonify ({"status" : "ok" })
38+
39+ # Setup Flask-RESTx with explicit prefix and doc URL
1240api = Api (
1341 app ,
1442 version = '1.0.0' ,
1543 title = 'Flask API' ,
1644 description = 'Flask API Documentation' ,
1745 doc = '/docs' , # Set documentation endpoint to /docs as requested
46+ prefix = '' , # Explicitly set empty prefix to avoid URL mapping issues
1847)
1948
20- # Get environment or use default
21- env = os .environ .get ("FLASK_ENV" , "development" )
22-
23- # Define namespaces
24- ns = api .namespace ('' , description = 'Core operations' )
49+ # Define namespaces - use '/api' prefix to avoid conflict with direct routes
50+ ns = api .namespace ('/api' , description = 'Core operations' )
2551
2652# Define models
2753service_info_model = api .model ('ServiceInfo' , {
4672 'data' : fields .Raw (example = {'key' : 'value' })
4773})
4874
49-
75+ # Flask-RESTX routes within the namespace
5076@ns .route ('/' )
51- class Root (Resource ):
77+ class ApiRoot (Resource ):
5278 @ns .response (200 , 'Success' , service_info_model )
5379 def get (self ):
54- """Root endpoint - returns basic service information"""
80+ """API root endpoint - returns basic service information"""
5581 return {
56- "message" : "Hello from Flask!" ,
82+ "message" : "Hello from Flask API Namespace !" ,
5783 "service" : "Flask API" ,
5884 "environment" : env ,
5985 "version" : "1.0.0" ,
6086 }
6187
62-
6388@ns .route ('/health' )
6489class Health (Resource ):
6590 @ns .response (200 , 'Success' , health_model )
6691 def get (self ):
6792 """Health check endpoint - returns service health status"""
6893 return {"status" : "healthy" , "service" : "Flask API" }
6994
70-
7195@ns .route ('/echo' )
7296class Echo (Resource ):
7397 @ns .expect (input_model , validate = True )
@@ -77,9 +101,24 @@ def post(self):
77101 data = request .get_json ()
78102 return {"echo" : data , "service" : "Flask API" }
79103
80- # Add a plain route outside of RESTx for simple health checks
81- @app .route ('/ping' )
82- def ping ():
83- return jsonify ({"status" : "ok" })
84-
85- # Gunicorn will run this, so no app.run() here.
104+ # Add the original '/health' endpoint at the root level (outside namespace)
105+ @app .route ('/health' )
106+ def health ():
107+ """Health check endpoint at root level"""
108+ return jsonify ({"status" : "healthy" , "service" : "Flask API" })
109+
110+ # Debug endpoint to help troubleshoot routing issues
111+ @app .route ('/debug/routes' )
112+ def debug_routes ():
113+ """Debug endpoint that shows all registered routes"""
114+ routes = []
115+ for rule in app .url_map .iter_rules ():
116+ routes .append ({
117+ 'endpoint' : rule .endpoint ,
118+ 'methods' : list (rule .methods ) if rule .methods else [],
119+ 'rule' : str (rule )
120+ })
121+ return jsonify (routes )
122+
123+ # Gunicorn will run this, so no app.run() here.
124+ # The app variable is imported by Gunicorn
0 commit comments