inital
This commit is contained in:
+175
@@ -0,0 +1,175 @@
|
||||
"""Application factory."""
|
||||
import os
|
||||
import logging
|
||||
from flask import Flask
|
||||
from config import get_config
|
||||
from app.extensions import db, migrate, bcrypt, cors, ma, limiter, session
|
||||
from app.middleware import RequestIDMiddleware, SecurityHeadersMiddleware, setup_cors
|
||||
from app.exceptions.base import BaseAPIException
|
||||
from app.utils.response import api_response
|
||||
import redis
|
||||
|
||||
|
||||
def create_app(config_name=None):
|
||||
"""
|
||||
Create and configure the Flask application.
|
||||
|
||||
Args:
|
||||
config_name: Configuration name (development, testing, production)
|
||||
|
||||
Returns:
|
||||
Flask application instance
|
||||
"""
|
||||
app = Flask(__name__)
|
||||
|
||||
# Load configuration
|
||||
config = get_config(config_name)
|
||||
app.config.from_object(config)
|
||||
|
||||
# Initialize extensions
|
||||
initialize_extensions(app)
|
||||
|
||||
# Setup middleware
|
||||
setup_middleware(app)
|
||||
|
||||
# Register blueprints
|
||||
register_blueprints(app)
|
||||
|
||||
# Register error handlers
|
||||
register_error_handlers(app)
|
||||
|
||||
# Setup logging
|
||||
setup_logging(app)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def initialize_extensions(app):
|
||||
"""Initialize Flask extensions."""
|
||||
# Database
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
|
||||
# Security
|
||||
bcrypt.init_app(app)
|
||||
|
||||
# CORS
|
||||
cors.init_app(
|
||||
app,
|
||||
origins=app.config.get("CORS_ORIGINS", []),
|
||||
supports_credentials=app.config.get("CORS_SUPPORTS_CREDENTIALS", True),
|
||||
)
|
||||
|
||||
# Marshmallow
|
||||
ma.init_app(app)
|
||||
|
||||
# Rate limiting
|
||||
if app.config.get("RATELIMIT_ENABLED"):
|
||||
limiter.init_app(app)
|
||||
|
||||
# Redis for sessions
|
||||
try:
|
||||
redis_url = app.config.get("REDIS_URL")
|
||||
if redis_url:
|
||||
redis_client = redis.from_url(redis_url)
|
||||
app.config["SESSION_REDIS"] = redis_client
|
||||
except Exception as e:
|
||||
app.logger.warning(f"Redis connection failed: {e}")
|
||||
|
||||
# Flask-Session
|
||||
session.init_app(app)
|
||||
|
||||
|
||||
def setup_middleware(app):
|
||||
"""Setup application middleware."""
|
||||
RequestIDMiddleware(app)
|
||||
SecurityHeadersMiddleware(app)
|
||||
setup_cors(app, cors)
|
||||
|
||||
|
||||
def register_blueprints(app):
|
||||
"""Register application blueprints."""
|
||||
from app.api import register_api_blueprints
|
||||
|
||||
register_api_blueprints(app)
|
||||
|
||||
|
||||
def register_error_handlers(app):
|
||||
"""Register error handlers."""
|
||||
|
||||
@app.errorhandler(BaseAPIException)
|
||||
def handle_api_exception(error):
|
||||
"""Handle custom API exceptions."""
|
||||
return api_response(
|
||||
success=False,
|
||||
message=error.message,
|
||||
status=error.status_code,
|
||||
error_type=error.error_type,
|
||||
error_details=error.error_details,
|
||||
)
|
||||
|
||||
@app.errorhandler(404)
|
||||
def handle_not_found(error):
|
||||
"""Handle 404 errors."""
|
||||
return api_response(
|
||||
success=False,
|
||||
message="Resource not found",
|
||||
status=404,
|
||||
error_type="NOT_FOUND",
|
||||
)
|
||||
|
||||
@app.errorhandler(405)
|
||||
def handle_method_not_allowed(error):
|
||||
"""Handle 405 errors."""
|
||||
return api_response(
|
||||
success=False,
|
||||
message="Method not allowed",
|
||||
status=405,
|
||||
error_type="METHOD_NOT_ALLOWED",
|
||||
)
|
||||
|
||||
@app.errorhandler(500)
|
||||
def handle_internal_error(error):
|
||||
"""Handle 500 errors."""
|
||||
app.logger.error(f"Internal server error: {error}")
|
||||
return api_response(
|
||||
success=False,
|
||||
message="Internal server error",
|
||||
status=500,
|
||||
error_type="INTERNAL_ERROR",
|
||||
)
|
||||
|
||||
@app.errorhandler(Exception)
|
||||
def handle_unexpected_error(error):
|
||||
"""Handle unexpected errors."""
|
||||
app.logger.error(f"Unexpected error: {error}", exc_info=True)
|
||||
return api_response(
|
||||
success=False,
|
||||
message="An unexpected error occurred",
|
||||
status=500,
|
||||
error_type="INTERNAL_ERROR",
|
||||
)
|
||||
|
||||
|
||||
def setup_logging(app):
|
||||
"""Setup application logging."""
|
||||
log_level = getattr(logging, app.config.get("LOG_LEVEL", "INFO"))
|
||||
|
||||
# Create formatter
|
||||
formatter = logging.Formatter(
|
||||
"[%(asctime)s] %(levelname)s in %(module)s: %(message)s"
|
||||
)
|
||||
|
||||
# Configure root logger
|
||||
if app.config.get("LOG_TO_STDOUT"):
|
||||
stream_handler = logging.StreamHandler()
|
||||
stream_handler.setFormatter(formatter)
|
||||
stream_handler.setLevel(log_level)
|
||||
app.logger.addHandler(stream_handler)
|
||||
|
||||
app.logger.setLevel(log_level)
|
||||
|
||||
# Reduce SQLAlchemy logging noise
|
||||
logging.getLogger('sqlalchemy').setLevel(logging.WARNING)
|
||||
|
||||
app.logger.info("Application startup")
|
||||
Reference in New Issue
Block a user