# =================================================================== # apps/weather_api/app.py # 날씨 API 서버 애플리케이션 # =================================================================== # 기상청 API 데이터를 제공하는 REST API 서버입니다. # 강수량 예보, 날씨 캡처 등의 기능을 제공합니다. # =================================================================== """ 날씨 API 서버 애플리케이션 기상청 API 데이터를 조회하고 가공하여 제공하는 API 서버입니다. 사용 예시: from apps.weather_api.app import create_app app = create_app() app.run() """ from flask import Flask, Blueprint, jsonify, request from werkzeug.exceptions import HTTPException from core.config import get_config from core.logging_utils import get_logger, setup_logging logger = get_logger(__name__) # Blueprint 생성 weather_bp = Blueprint('weather', __name__, url_prefix='/api/weather') @weather_bp.route('/health', methods=['GET']) def health_check(): """헬스 체크""" return jsonify({ 'status': 'healthy', 'service': 'weather-api' }) @weather_bp.route('/precipitation', methods=['GET']) def get_precipitation(): """ 시간별 강수량 예보 조회 Query Parameters: date: 조회 날짜 (YYYYMMDD, 기본: 오늘) format: 출력 형식 (json, html, text) Returns: 강수량 예보 데이터 """ from services.weather import PrecipitationService target_date = request.args.get('date') output_format = request.args.get('format', 'json') try: service = PrecipitationService() data = service.get_precipitation_info( target_date=target_date, output_format=output_format ) if output_format == 'html': return data, 200, {'Content-Type': 'text/html; charset=utf-8'} elif output_format == 'text': return data, 200, {'Content-Type': 'text/plain; charset=utf-8'} else: return jsonify({ 'status': 'success', 'data': data }) except Exception as e: logger.error(f"강수량 조회 실패: {e}") return jsonify({'error': str(e)}), 500 @weather_bp.route('/forecast/ultra', methods=['GET']) def get_ultra_forecast(): """ 초단기예보 조회 Returns: 초단기예보 데이터 """ from services.weather import get_daily_ultra_forecast config = get_config() service_key = config.data_api.get('service_key') or config.weather_service.get('service_key', '') if not service_key: return jsonify({'error': 'API 키가 설정되지 않았습니다.'}), 500 try: data = get_daily_ultra_forecast(service_key) return jsonify({ 'status': 'success', 'type': 'ultra', 'data': data }) except Exception as e: logger.error(f"초단기예보 조회 실패: {e}") return jsonify({'error': str(e)}), 500 @weather_bp.route('/forecast/vilage', methods=['GET']) def get_vilage_forecast(): """ 단기예보 조회 Returns: 단기예보 데이터 """ from services.weather import get_daily_vilage_forecast config = get_config() service_key = config.data_api.get('service_key') or config.weather_service.get('service_key', '') if not service_key: return jsonify({'error': 'API 키가 설정되지 않았습니다.'}), 500 try: data = get_daily_vilage_forecast(service_key) return jsonify({ 'status': 'success', 'type': 'vilage', 'data': data }) except Exception as e: logger.error(f"단기예보 조회 실패: {e}") return jsonify({'error': str(e)}), 500 @weather_bp.route('/forecast/midterm', methods=['GET']) def get_midterm_forecast(): """ 중기예보 조회 Query Parameters: reg_id: 지역 코드 (기본: 11B20305) Returns: 중기예보 데이터 """ from services.weather import get_midterm_forecast as fetch_midterm config = get_config() service_key = config.data_api.get('service_key') or config.weather_service.get('service_key', '') reg_id = request.args.get('reg_id', '11B20305') if not service_key: return jsonify({'error': 'API 키가 설정되지 않았습니다.'}), 500 try: precip_probs, raw_data = fetch_midterm(service_key, reg_id) return jsonify({ 'status': 'success', 'type': 'midterm', 'precipitation_probability': precip_probs, 'raw_data': raw_data }) except Exception as e: logger.error(f"중기예보 조회 실패: {e}") return jsonify({'error': str(e)}), 500 @weather_bp.errorhandler(HTTPException) def handle_exception(e): """HTTP 예외 핸들러""" return jsonify({ 'error': e.description, 'status_code': e.code }), e.code def create_app(config_override: dict = None) -> Flask: """ Flask 애플리케이션 팩토리 Args: config_override: 설정 덮어쓰기 딕셔너리 Returns: Flask 앱 인스턴스 """ app = Flask(__name__) # 설정 로드 config = get_config() app.config['SECRET_KEY'] = config.flask.get('secret_key', 'dev-secret') app.config['JSON_AS_ASCII'] = False if config_override: app.config.update(config_override) # 로깅 설정 setup_logging('apps.weather_api', level=config.log_level) # Blueprint 등록 app.register_blueprint(weather_bp) # 루트 엔드포인트 @app.route('/') def index(): return jsonify({ 'name': 'FGTools Weather API', 'version': '1.0.0', 'endpoints': [ '/api/weather/health', '/api/weather/precipitation', '/api/weather/forecast/ultra', '/api/weather/forecast/vilage', '/api/weather/forecast/midterm', ] }) logger.info("Weather API 앱 초기화 완료") return app def run_server(host: str = '0.0.0.0', port: int = 5001, debug: bool = False): """ 개발 서버 실행 Args: host: 바인딩 호스트 port: 포트 번호 debug: 디버그 모드 """ app = create_app() app.run(host=host, port=port, debug=debug) if __name__ == '__main__': config = get_config() run_server( host=config.flask.get('host', '0.0.0.0'), port=5001, debug=config.debug )