115 lines
4.2 KiB
Python
115 lines
4.2 KiB
Python
from flask import Flask, request, jsonify, make_response
|
|
import requests
|
|
import json
|
|
from urllib.parse import urlparse
|
|
import logging
|
|
|
|
# Configure basic logging
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Initialize Flask app
|
|
MyApp = Flask(__name__)
|
|
MyApp.config['SECRET_KEY'] = 'your-secret-key-here'
|
|
|
|
class ResourceRouter:
|
|
def __init__(self):
|
|
self.resource_mappings = {
|
|
'login': {'backend_url': 'http://linepe.de:5004/login', 'methods': ['POST']},
|
|
'logout': {'backend_url': 'http://linepe.de:5004/logout', 'methods': ['POST']},
|
|
'register': {'backend_url': 'http://linepe.de:5004/register', 'methods': ['POST']},
|
|
'listing': {'backend_url': 'http://linepe.de:5005/listing', 'methods': ['GET', 'POST', 'PUT', 'DELETE']},
|
|
'listings': {'backend_url': 'http://linepe.de:5005/listings', 'methods': ['GET', 'POST', 'PUT', 'DELETE']}
|
|
}
|
|
|
|
def get_backend_info(self, resource_path):
|
|
"""Get backend URL and allowed methods based on the resource path"""
|
|
return self.resource_mappings.get(resource_path)
|
|
|
|
def is_valid_request(self, resource_path, method):
|
|
"""Check if the request path and method are valid"""
|
|
backend_info = self.get_backend_info(resource_path)
|
|
if not backend_info:
|
|
return False
|
|
return method in backend_info['methods']
|
|
|
|
resource_router = ResourceRouter()
|
|
|
|
def handle_backend_response(response):
|
|
"""Helper function to handle backend responses"""
|
|
if not response.ok:
|
|
logger.error(f"Backend request failed with status code {response.status_code}")
|
|
# Check if the response has a valid Content-Type header for JSON
|
|
if response.headers.get('Content-Type', '').startswith('application/json'):
|
|
try:
|
|
logger.error(f"Errormessage {response.json()}")
|
|
except ValueError as e:
|
|
logger.error(f"Failed to parse JSON response: {e}")
|
|
else:
|
|
# If the response isn't JSON, log the raw response content
|
|
logger.error(f"Non-JSON response received: {response.text}")
|
|
if not response.json():
|
|
return jsonify({"error": f"Failed to process request"}), 500
|
|
else:
|
|
return response.json(), response.status_code
|
|
try:
|
|
data = response.json()
|
|
return jsonify(data), response.status_code
|
|
except json.JSONDecodeError:
|
|
logger.error("Failed to decode backend response")
|
|
return jsonify({"error": "Invalid response format"}), 500
|
|
|
|
@MyApp.route('/')
|
|
def home():
|
|
"""Health check endpoint"""
|
|
return jsonify({'status': 'ok', 'message': 'API gateway is running'})
|
|
|
|
@MyApp.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
|
|
def generic_proxy(path):
|
|
"""Generic route handler for all API resources"""
|
|
|
|
if "/" in path:
|
|
route_parts = path.split('/')
|
|
resource = route_parts[0]
|
|
listing_id = route_parts[1]
|
|
elif "?" in path:
|
|
route_parts = path.split('?')
|
|
resource = route_parts[0]
|
|
else:
|
|
resource = path
|
|
|
|
if not resource_router.is_valid_request(resource, request.method):
|
|
return jsonify({"error": "Invalid path or method"}), 405
|
|
|
|
backend_info = resource_router.get_backend_info(resource)
|
|
backend_url = backend_info['backend_url']
|
|
|
|
# Extract all query parameters
|
|
query_params = dict(request.args)
|
|
|
|
try:
|
|
data = {}
|
|
|
|
if request.is_json and request.json:
|
|
data.update(request.json)
|
|
|
|
# Append listing_id to the URL if present in query parameters
|
|
if "/" in path:
|
|
backend_url += f"/{listing_id}"
|
|
|
|
# Make the request to the backend service
|
|
response = requests.request(
|
|
method=request.method,
|
|
url=backend_url,
|
|
json=data,
|
|
params=query_params, # Send all remaining query parameters as part of the request
|
|
headers=request.headers
|
|
)
|
|
|
|
return handle_backend_response(response)
|
|
except Exception as e:
|
|
logger.error(f"Error proxying request: {str(e)}")
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
if __name__ == '__main__':
|
|
MyApp.run(debug=True, port=5000) |