Flask 설치 및 개요
Flask는 파이썬으로 작성된 경량화 및 높은 확장성을 자랑하는 WSGI 웹 애플리케이션 프레임워크입니다. 최소한의 핵심 기능만 제공하며, 필요한 기능은 확장 모듈을 통해 추가할 수 있는 마이크로서비스 아키텍처에 적합한 구조를 가지고 있습니다. 특히 스레드 로컬(Thread Local) 기반의 컨텍스트 관리 메커니즘이 뛰어나다는 점이 큰 장점입니다.
pip3 install Flask
WSGI와 Werkzeug 기반 동작 원리
Flask는 라우팅 및 요청/응답 처리를 위해 Werkzeug라는 WSGI 유틸리티 라이브러리에 의존합니다. Flask를 설치하면 Werkzeug도 함께 설치됩니다. 프레임워크의底层 동작을 이해하기 위해 Werkzeug를 직접 활용한 WSGI 애플리케이션 구현을 살펴볼 수 있습니다.
WSGI 기본 구현
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple
def handle_request(environ, start_response):
response = Response("WSGI Response Active", mimetype='text/plain')
return response(environ, start_response)
if __name__ == '__main__':
run_simple('127.0.0.1', 5000, handle_request)
Flask의 __call__ 매직 메서드 활용 원리
Flask의 핵심 클래스는 WSGI 서버로부터 요청을 받기 위해 __call__ 매직 메서드를 구현하고 있습니다. 이를 통해 클래스의 인스턴스를 함수처럼 호출할 수 있습니다.
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple
class CustomFramework:
def __call__(self, environ, start_response):
res = Response('Framework Initialized')
return res(environ, start_response)
def serve(self):
run_simple('127.0.0.1', 8000, self)
app_instance = CustomFramework()
if __name__ == '__main__':
app_instance.serve()
기본 애플리케이션 구조
Flask를 사용하여 가장 기본적으로 웹 서버를 구동하는 구조는 인스턴스화, 라우트 정의, 실행의 세 단계로 나뉩니다.
from flask import Flask
web_app = Flask(__name__)
@web_app.route('/home')
def home_page():
return "Welcome to the Home Page"
if __name__ == '__main__':
web_app.run(debug=True)
동적 모듈 및 클래스 로딩
문자열 경로 기반으로 모듈과 클래스를 동적으로 임포트하여 설정값을 추출하는 방식은 프레임워크 내부에서 설정 파일을 로드할 때 자주 사용되는 패턴입니다. importlib을 활용하여 구현할 수 있습니다.
import importlib
target_module_path = "app_config.DatabaseSettings"
module_part, class_part = target_module_path.rsplit('.', maxsplit=1)
loaded_module = importlib.import_module(module_part)
TargetClass = getattr(loaded_module, class_part)
for attribute in dir(TargetClass):
if attribute.isupper():
print(f"{attribute} = {getattr(TargetClass, attribute)}")
핵심 시스템 컴포넌트
1. 환경 설정 (Configuration)
클래스 기반의 설정 관리를 통해 개발, 테스트, 프로덕션 환경을 분리할 수 있습니다.
# settings.py
class BaseSettings:
DEBUG = False
SECRET_KEY = 'default-secret'
class DevEnvironment(BaseSettings):
DEBUG = True
DATABASE_URI = 'sqlite:///dev.db'
# app.py
web_app.config.from_object("settings.DevEnvironment")
2. 라우팅 시스템 (Routing)
URL 규칙 정의, 타입 변환, 그리고 url_for을 통한 역방향 해석(Reverse Resolution)을 지원합니다. 또한 Werkzeug의 BaseConverter를 상속받아 커스텀 정규식 라우팅을 구현할 수 있습니다.
from werkzeug.routing import BaseConverter
class HexadecimalConverter(BaseConverter):
regex = '[0-9a-fA-F]+'
def to_python(self, value):
return int(value, 16)
def to_url(self, value):
return hex(value).lstrip('0x')
web_app.url_map.converters['hex'] = HexadecimalConverter
@web_app.route('/asset/', endpoint='asset_detail')
def fetch_asset(asset_id):
# url_for('asset_detail', asset_id=255) -> '/asset/ff'
return f"Decimal Asset ID: {asset_id}"
3. 뷰 (Views: FBV 및 CBV)
함수 기반 뷰(FBV) 외에도 MethodView를 활용한 클래스 기반 뷰(CBV)를 지원하여 RESTful API 설계에 용이합니다.
from flask import views
class DataEndpoint(views.MethodView):
methods = ['GET', 'POST']
def get(self):
return "Data retrieved"
def post(self):
return "Data created"
web_app.add_url_rule('/data', view_func=DataEndpoint.as_view('data_api'))
4. 요청 및 응답 객체 (Request & Response)
request 객체를 통해 클라이언트의 요청 데이터를 파싱하고, make_response를 통해 응답 헤더와 쿠키를 세밀하게 제어할 수 있습니다.
from flask import request, jsonify, make_response
@web_app.route('/process', methods=['POST'])
def process_data():
payload = request.json
token = request.headers.get('Authorization')
resp = make_response(jsonify({"status": "success", "data": payload}))
resp.headers['X-Custom-Header'] = 'Processed'
resp.set_cookie('session_token', token)
return resp
5. 템플릿 엔진 (Jinja2)
Jinja2 템플릿 엔진을 사용하며, 커스텀 필터와 글로벌 함수를 등록하여 템플릿 내에서의 로직 처리를 확장할 수 있습니다. XSS 방지를 위한 safe 필터와 Markup 클래스도 제공됩니다.
@web_app.template_filter('currency')
def format_currency(amount, symbol='$'):
return f"{symbol}{amount:,.2f}"
@web_app.template_global()
def calculate_tax(price, rate=0.1):
return price * rate
# 템플릿 사용 예시: {{ price|currency('€') }} / {{ calculate_tax(100) }}
6. 세션 및 플래시 메시지 (Session & Flash)
Flask의 세션은 서버 메모리가 아닌 클라이언트의 쿠키에 암호화하여 저장하는 방식을 기본으로 사용합니다. 플래시(Flash) 메시지는 세션을 기반으로 하며, 한 번 읽으면 자동으로 소멸되는 일회성 메시지 전달에 사용됩니다.
from flask import session, flash, get_flashed_messages
@web_app.route('/set-message')
def set_message():
flash("Operation completed successfully", category="info")
return "Message set"
@web_app.route('/get-message')
def get_message():
messages = get_flashed_messages(category_filter=["info"])
return str(messages)
7. 미들웨어 및 생명주기 훅 (Middleware & Hooks)
WSGI 미들웨어를 구현하여 요청이 Flask 애플리케이션에 도달하기 전/후의 로직을 가로챌 수 있으며, before_request와 after_request 데코레이터를 통해 애플리케이션 레벨의 생명주기 훅을 정의할 수 있습니다.
class RequestInterceptor:
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, environ, start_response):
print("Intercepting request at WSGI level...")
return self.wsgi_app(environ, start_response)
web_app.wsgi_app = RequestInterceptor(web_app.wsgi_app)
@web_app.before_request
def authenticate_user():
print("Executing before request routing...")
@web_app.after_request
def add_security_headers(response):
response.headers['X-Frame-Options'] = 'DENY'
return response
블루프린트를 활용한 프로젝트 구조화
단일 파일 구조를 벗어나 대규모 프로젝트로 확장할 때는 블루프린트(Blueprint)를 사용하여 애플리케이션을 모듈화합니다. 블루프린트는 라우트, 뷰, 템플릿, 정적 파일 등을 논리적으로 그룹화하여 독립적인 컴포넌트처럼 다루게 해주며, 최종적으로 메인 Flask 인스턴스에 등록되어 통합된 URL 맵을 형성합니다. 이를 통해 도메인 주도 설계(DDD)나 기능별 디렉토리 구조를 체계적으로 구축할 수 있습니다.