Starlette를 통한 FastAPI의 핵심 구성 요소 이해
Emily Parker
Product Engineer · Leapcell

소개
FastAPI는 Python 생태계에서 가장 사랑받는 웹 프레임워크 중 하나로 빠르게 자리매김했습니다. 놀라운 속도, 자동 데이터 유효성 검사, 원활한 OpenAPI 통합 등의 장점으로 극찬받고 있습니다. 개발자들은 종종 우아한 API와 인상적인 성능에 감탄하지만, 이 모든 것을 가능하게 하는 기본 아키텍처를 진정으로 이해하는 사람은 드뭅니다. 그 비밀은 바로 강력한 기반인 Starlette에 있습니다. Starlette는 매우 높은 성능의 비동기 서비스를 구축하기 위해 설계된 경량 ASGI 프레임워크/툴킷으로, FastAPI가 구축된 기반입니다. Starlette의 핵심 구성 요소, 즉 요청(Request), 응답(Response), 라우팅(Routing) 및 미들웨어(Middleware)를 이해하는 것은 FastAPI의 잠재력을 최대한 활용하거나, 복잡한 문제를 해결하거나, 심지어 개발에 기여하려는 모든 사람에게 중요합니다. 이 심층 분석은 FastAPI의 강력한 기능을 뒷받침하는 필수 메커니즘을 밝혀, 단순히 FastAPI를 사용하는 단계에서 이를 진정으로 이해하는 단계로 나아가게 할 것입니다.
Starlette의 핵심 구성 요소
실질적인 내용을 살펴보기 전에 Starlette와 그 확장인 FastAPI를 뒷받침하는 기본 개념을 정의해 보겠습니다.
- ASGI (Asynchronous Server Gateway Interface): 비동기 Python 웹 서버와 비동기 Python 웹 애플리케이션 간의 일반적인 인터페이스 사양입니다. Starlette는 ASGI 프레임워크이므로 이 사양을 준수하여 Uvicorn이나 Hypercorn와 같은 ASGI 서버와 원활하게 작동할 수 있습니다.
 - Request: 웹 애플리케이션의 맥락에서 Request 객체는 클라이언트(예: 웹 브라우저)가 서버로 보낸 모든 정보를 캡슐화합니다. 여기에는 HTTP 헤더, URL 매개변수, 쿼리 문자열, 본문 내용(JSON 또는 폼 데이터 등) 및 HTTP 메서드가 포함됩니다.
 - Response: 반대로 Response 객체는 서버가 클라이언트로 다시 보내는 데이터를 나타냅니다. 여기에는 HTTP 상태 코드, 헤더 및 실제 내용(예: HTML, JSON 또는 파일)이 포함됩니다.
 - Routing: 들어오는 HTTP 요청을 애플리케이션 내의 특정 핸들러 함수 또는 뷰로 매핑하는 프로세스입니다. 요청의 URL 경로와 HTTP 메서드를 기반으로 라우터는 어떤 코드 조각을 실행할지 결정합니다.
 - Middleware: 미들웨어 구성 요소는 서버와 애플리케이션 사이에 위치하는 함수 또는 클래스입니다. 들어오는 요청과 나가는 응답을 가로채서 인증, 로깅, 오류 처리, 헤더 추가와 같은 일반적인 작업을 수행할 수 있게 하여 기본 애플리케이션 로직을 깔끔하게 유지합니다.
 
요청 처리
Starlette의 Request 객체는 들어오는 클라이언트 요청의 모든 측면에 액세스할 수 있는 포괄적인 유틸리티입니다. 요청 본문을 읽기 위한 비동기 메서드를 제공하여 대용량 데이터 스트림을 효율적으로 처리할 수 있습니다.
# main.py from starlette.applications import Starlette from starlette.routing import Route from starlette.responses import JSONResponse import uvicorn async def homepage(request): # 쿼리 매개변수 액세스 name = request.query_params.get("name", "World") # 헤더 액세스 user_agent = request.headers.get("user-agent", "Unknown") return JSONResponse({"message": f"Hello, {name}!", "user_agent": user_agent}) async def submit_data(request): if request.method == "POST": # JSON 본문을 비동기적으로 읽기 data = await request.json() return JSONResponse({"received_data": data, "message": "Data processed!"}) return JSONResponse({"message": "Please send a POST request with JSON data."}, status_code=400) routes = [ Route("/", homepage), Route("/submit", submit_data, methods=["POST"]), ] app = Starlette(routes=routes) if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)
이 예에서 homepage는 쿼리 매개변수와 헤더를 검색하는 방법을 보여줍니다. submit_data 함수는 await request.json()을 사용하여 JSON 요청 본문을 비동기적으로 구문 분석하는 방법을 보여줍니다. FastAPI는 Starlette의 Request 객체를 활용하지만, 라우트 함수 인수에서 Pydantic 모델을 통해 이러한 수동 구문 분석을 편리하게 추상화하여 데이터를 자동으로 유효성 검사하고 역직렬화합니다.
응답 생성
Starlette는 다양한 콘텐츠 유형에 대한 Response 클래스 모음을 제공하여 올바른 Content-Type 헤더와 효율적인 데이터 직렬화를 보장합니다. 일반적인 유형으로는 JSONResponse, HTMLResponse, PlainTextResponse, RedirectResponse, StreamingResponse, FileResponse 등이 있습니다.
# main.py (이전 예제에서 계속) from starlette.responses import HTMLResponse, PlainTextResponse, RedirectResponse async def html_page(request): content = "<h1>Welcome to Starlette!</h1><p>This is an HTML response.</p>" return HTMLResponse(content) async def plain_text(request): return PlainTextResponse("This is a plain text response.") async def redirect_example(request): return RedirectResponse(url="/", status_code=302) routes = [ Route("/", homepage), Route("/submit", submit_data, methods=["POST"]), Route("/html", html_page), Route("/text", plain_text), Route("/redirect", redirect_example), ] app = Starlette(routes=routes)
여기서는 HTMLResponse, PlainTextResponse, RedirectResponse를 보여주는 라우트를 추가했습니다. FastAPI 라우트에서 Pydantic 모델이나 딕셔너리를 반환하면 FastAPI는 내부적으로 Starlette의 JSONResponse를 사용하여 데이터를 JSON으로 직렬화합니다.
라우팅 메커니즘
Starlette의 라우팅은 선언적이고 강력하여 특정 비동기 함수에 URL 경로를 매핑할 수 있습니다. URL 내의 동적 세그먼트인 경로 매개변수를 지원합니다.
# main.py (계속) async def user_profile(request): user_id = request.path_params["user_id"] return JSONResponse({"user_id": user_id, "message": f"Fetching profile for user {user_id}"}) routes = [ Route("/", homepage), Route("/submit", submit_data, methods=["POST"]), Route("/html", html_page), Route("/text", plain_text), Route("/redirect", redirect_example), Route("/users/{user_id}", user_profile), # 경로 매개변수 ] app = Starlette(routes=routes)
Route("/users/{user_id}", user_profile) 줄은 경로 매개변수 {user_id}를 가진 라우트를 정의합니다. 이 값은 request.path_params["user_id"]를 통해 액세스할 수 있습니다. FastAPI는 함수 서명에 경로 매개변수를 직접 선언할 수 있도록 하여(def read_user(user_id: int):) 이를 더욱 단순화합니다.
교차 관심사 처리를 위한 미들웨어
미들웨어는 Starlette의 교차 관심사를 처리하는 강력함이 빛을 발하는 부분입니다. 애플리케이션을 감싸서 요청의 사전 처리 및 응답의 사후 처리를 허용합니다. Starlette는 CORSMiddleware, GZipMiddleware, Middleware(사용자 정의 미들웨어용)와 같은 여러 내장 미들웨어를 제공합니다.
# main.py from starlette.middleware import Middleware from starlette.middleware.cors import CORSMiddleware from starlette.middleware.gzip import GZipMiddleware import time # 사용자 정의 미들웨어 async def custom_middleware(request, call_next): start_time = time.time() response = await call_next(request) process_time = time.time() - start_time response.headers["X-Process-Time"] = str(process_time) print(f"Request to {request.url.path} processed in {process_time:.4f} seconds") return response middleware = [ Middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]), Middleware(GZipMiddleware, minimum_size=1000), # 내용 크기가 1KB보다 크면 응답 압축 Middleware(custom_middleware), # 사용자 정의 로깅/타이밍 미들웨어 ] app = Starlette(routes=routes, middleware=middleware)
여기서는 세 가지 미들웨어를 연결했습니다. 교차 출처 리소스 공유를 처리하는 CORSMiddleware, 응답을 자동으로 압축하는 GZipMiddleware, 요청 타이밍을 위한 custom_middleware입니다. 각 미들웨어는 request 객체와 call_next 함수를 받습니다. await call_next(request)를 호출하면 다음 미들웨어나 애플리케이션 자체로 제어가 전달됩니다. call_next 함수에서 받은 응답은 반환되기 전에 수정할 수 있습니다. FastAPI는 유사한 app.add_middleware() 인터페이스를 노출하여 Starlette의 미들웨어 시스템을 투명하게 활용합니다.
결론
Starlette는 FastAPI에 높은 성능과 모듈성을 제공하는 강력한 비동기 기반을 제공합니다. Request 및 Response 객체, 선언적 Routing, 다목적 Middleware 시스템을 이해함으로써 개발자는 FastAPI가 요청을 처리하고, 응답을 생성하며, 일반적인 웹 애플리케이션 문제를 처리하는 방법에 대한 통찰력을 얻을 수 있습니다. 이 기본 지식은 더 효율적이고 유지보수하기 쉬우며 강력한 웹 서비스를 구축하는 데 중요하며, 단순히 외관만 사용하는 것이 아니라 기본 메커니즘을 진정으로 활용할 수 있게 해줍니다. 궁극적으로 Starlette는 개발자 친화적인 경험과 번개처럼 빠른 코어를 결합한 FastAPI를 위한 고성능 비동기 기본 요소를 제공합니다.