[파이썬 Projects]/<파이썬 웹개발>

[파이썬] FastAPI - 정적 파일, API Router

기록자_Recordian 2025. 4. 27. 16:30
728x90
반응형
이전 내용
 

[파이썬] FastAPI - FastAPI와 Jinja2 고급 문법

시작에 앞서해당 내용은 , Dave Lee 지음. BJ Public 출판.내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.이전 내용 [파이썬] FastAPI - 템플릿시작에 앞서해당

puppy-foot-it.tistory.com


정적 파일 (static files)

 

◆ 정적 파일(static files)

정적 파일이란 서버에서 클라이언트에게 전송되는 파일 중 내용이 변하지 않고 일정한 파일을 의미합니다. 주로 HTML, CSS, JavaScript, 이미지 파일(jpg, png, gif 등) 등이 포함된다. 이러한 파일들은 웹사이트의 렌더링에 필요한 기본 요소를 제공하며, 사용자가 요청할 때마다 그대로 전송된다.

[정적 파일의 특징]

  • 불변성: 콘텐츠가 변경되지 않고, 매번 동일한 결과 제공.
  • 성능: 서버에서 반복적으로 생성할 필요가 없으므로 빠르게 전송.
  • 호스팅 용이성: 정적 파일은 복잡한 서버 사이드 프로세스를 필요로 하지 않으므로, 클라우드 스토리지나 CDN(콘텐츠 전송 네트워크)을 통해 쉽게 호스팅.

이와 반대로, 동적 파일은 사용자의 요청에 따라 콘텐츠가 변화하는 파일을 지칭한다. 예를 들어, 데이터베이스에서 정보를 기반으로 생성된 웹페이지가 이에 해당한다.


FastAPI에서 정적 파일 다루기

 

FastAPI에서 정적 파일을 다뤄보기 위해 먼저 main.py 코드 파일이 있는 폴더에서 static이라는 하위 폴더를 생성하고, 이미지 하나를 넣어준다.

그리고나서, FastAPI에서 정적 파일을 설정한다.

app.mount() 메소드를 사용해서 /static 이라는 URL 경로와 static 디렉토리를 연결해주고, 이를 static 이라는 이름으로 지정했다.

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles

app = FastAPI()

app.mount("/static", StaticFiles(directory='static'), name="static")
  • directory: 정적 파일들이 어디에 있는지 알려주는 것
  • name: 마운트한 정적 파일 설정에 이름을 붙여주는 것으로, 디버깅이나 문서화할 때 쓰임.
  • 마운트: 특정 URL 경로와 실제 디렉토리(또는 다른 애플리케이션)를 연결해주는 것.

이제 이를 테스트 하기 위해 서버를 켜고 하단의 링크로 들어가면

http://127.0.0.1:8000/static/cat(파일명).jpg

 

지정한 이미지가 잘 나온다.


정적 파일과 웹 페이지 구현

 

FastAPI를 사용하여 웹 애플리케이션을 개발할 때 index.html과 함께 정적 파일을 관리하고 제공하는 것은 중요하다.

아래와 같은 프로젝트 폴더 구조가 있다.

  • static: 정적 파일이 저장되는 폴더
  • templates: HTML 파일이 저장되는 폴더
  • main.py: FastAPI 애플리케이션의 진입점

[main.py]

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

app = FastAPI()

# 정적 파일을 위한 설정
app.mount("/static", StaticFiles(directory='static'), name="static")

templates = Jinja2Templates(directory="templates")

# 메인 페이지 라우트
@app.get("/")
def read_root(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

▶ StaticFiles를 사용하여 /static 경로로 들어오는 요청을 static 폴더에서 처리하도록 설정한다.

 

[index.html]

<!DOCTYPE html>
<html>
<head>
	<title>FastAPI and Static Files</title>
</head>
<body>
    <h1>Welcome to FastAPI!</h1>
    <img src="/static/cat.jpg" alt="example image">
</body>
</html>

▶ /static/cat.jpg 라는 경로로 이미지 파일을 불러온다.

 

main.py 파일을 실행하고

http://127.0.0.1:8000/ 로 접속해서 이미지가 보이면 된다.

 

이렇게 static과 templates 폴더를 분리함으로써 코드의 관리가 쉬워지며, 효율적인 캐싱이 가능하다.

또한, FastAPI는 정적 파일에 대한 안전한 접근을 보장해 주기 때문에 FastAPI에서 정적 파일과 index.html 을 활용하면 웹 애플리케이션의 성능과 유지보수성, 보안이 향상된다.


API Router

 

FastAPI의 API Router는 애플리케이션의 라우팅 기능을 모듈화하고 조직화하는 데 있어 매우 유용한 도구다. 여러 엔드포인트를 그룹화하고, 더 깔끔하고 관리하기 쉬운 구조를 유지하는 데 도움을 준다.

  • 라우터(Router): FastAPI에서 라우터는 특정 경로에 대한 API 엔드포인트를 정의하는 클래스로, 여러 엔드포인트를 그룹화하여 관리할 수 있는 기능 제공.
  • 모듈화: 라우터를 사용하면 코드의 모듈화를 통해 기능별로 API를 조직하고, 각각의 엔드포인트를 독립적으로 작성 가능.

FastAPI에서 API Router를 사용하려면 먼저 fastapi 패키지에서 APIRouter를 임포트하고, APIRouter 객체를 생성한다.

그리고나서 이제 이 router에 라우터를 추가할 수 있으며, FastAPI 애플리케이션에 포함시키면 된다.

from fastapi import APIRouter

router = APIRouter()

# router에 라우트 추가
@router.get("/items")
def read_items():
    return {"Hello": "World!"}
    
# FastAPI 애플리케이션에 router 포함
app.include_router(router)

 

서버를 실행한 후, 하단의 경로로 접속해보면

http://127.0.0.1:8000/items

설정한 게 잘 출력되는 것을 확인할 수 있다.


APIRouter의 다양한 사용법

 

  • 기본 사용법: app.include_router(router)로 라우터를 애플리케이션에 포함.
  • Prefix 사용: app.include_router(router, prefix="/api")로 모든 엔드포인트에 접두사 추가.
  • Tags 사용: app.include_router(router, tags=["Items"])로 Swagger UI에서 엔드포인트를 그룹화.
  • 메서드 제한: app.include_router(router, methods=["GET"])로 특정 HTTP 메서드만 포함.
  • Dependencies 사용: app.include_router(router, dependencies [Depends(common_parameters])로 의존성을 모든 엔드포인트에 적용.
  • Responses 및 Status Codes 설정: app.include_router(router, responses={404: {"description": "Not found"}})로 응답을 사용자 지정.
  • Router 이름 및 고유성 설정: app.include_router(router, name="item_router")로 고유한 이름 부여.

그 외 자세한 내용은

https://fastapi.tiangolo.com/reference/apirouter/#fastapi.APIRouter--example

 

APIRouter class - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

 

[URL 접두사와 태그 테스트]

main.py에 APIRouter를 사용하여 두 개의 라우트를 정의하고, include_router() 함수에서 prefix와 tags 옵션을 설정한 코드를 작성한다.

from fastapi import APIRouter

app = FastAPI()
router = APIRouter()

# router에 라우트 추가
@router.get("/items")
def read_items():
    return {"item": "apple"}
    
@router.get("/users")
def read_users():
    return {"user": "Jun"}

# FastAPI 애플리케이션에 router 포함
app.include_router(router, prefix="/api/v1", tags=["items"])

 

그리고 서버를 실행한 후, 하단의 링크로 접속하여 API 문서를 확인한다.

http://127.0.0.1:8000/docs

필자의 경우엔, main.py에 메인 페이지 라우터도 놔둬서 default 부분이 같이 뜬다.

 

여기서 items 태그를 확인할 수 있으며, 이 태그를 클릭하면 /api/v1/items와 api/v1/users 라우트 정보가 나타난다.

물론, 두 링크로 들어가도 JSON 형식의 결과를 확인할 수 있다.

http://127.0.0.1:8000/api/v1/items

http://127.0.0.1:8000/api/v1/users

 


미들웨어 설정

 

FastAPI에서 APIRouter 객체는 미들웨어를 직접 추가할 수 없으나, 미들웨어는 FastAPI 애플리케이션 인스턴스에 추가하여 이 인스턴스에 APIRouter를 포함시킬 수 있다.

[미들웨어란?]
FastAPI에서 미들웨어(Middleware)는 요청 처리 과정에서 특정 작업을 수행할 수 있는 기능으로, 요청과 응답 사이에 개입하여 기능을 추가하거나 변환할 수 있다. 미들웨어는 애플리케이션의 모든 요청 및 응답에 대해 동작하며, 주로 인증, 로깅, 세션 관리, CORS 설정 등 다양한 목적을 위해 사용된다.

- 미들웨어 정의: 미들웨어는 요청이 애플리케이션에 도달하기 전에 또는 응답이 클라이언트에 도달하기 전에 실행되는 함수를 정의할 수 있다.
- 요청과 응답의 수정: 미들웨어는 요청의 내용을 수정하거나, 응답을 변경할 수 있는 권한을 가진다.

 

TrustedHostMiddleware는 FastAPI에서 요청을 처리할 때 허용된 호스트의 목록을 검사하는 미들웨어다. 이 미들웨어는 보안 측면에서 중요한 역할을 하며, 서버가 수신할 수 있는 호스트를 제한함으로써 HTTP Host 헤더 위변조를 방지한다.

TrustedHostMiddleware를 사용하려면 add_middleware 메서드를 통해 FastAPI 애플리케이션에 추가하면 된다.

from fastapi import APIRouter
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app = FastAPI()
router = APIRouter()

app.add_middleware(
    TrustedHostMiddleware,
    allowed_hosts = ["example.com", "localhost", "127.0.0.1"]
)

# APIRouter를 사용한 라우트
@router.get("/items")
def read_items_from_router():
    return {"message": "You are accessing the API from an allowed host via router."}
    
@router.get("/hello")
def read_hello():
    return {"message": "Hello"}

# FastAPI 애플리케이션에 router 포함
app.include_router(router, prefix="/api")
  • APIRouter를 통한 라우트(허용된 호스트에서만 접근 가능): http://127.0.0.1:8000/api/items ▶ 개인 PC에서 접속 시 접속이 허용됨
  • 메인 애플리케이션을 통한 일반 라우드(모든 호스트에서 접근 가능): http://127.0.0.1:8000/hello

APIRouter와 의존성 함수

 

의존성(dependency) 함수는 FastAPI에서 특정 라우터나 엔드포인트가 실행되기 전에 수행되는 함수이며, 일반적으로 인증, 권한 확인, 데이터 검증 등을 수행한다.

  • Depends(): 의존성을 설정하는 데 사용하는 함수
  • APIRouter: dependencies 매개변수를 이용하여 라우터 레벨에서 의존성 설정 가능. ▶ APIRouter(dependencies=[Depends(의존성함수)]

사용자가 특정 토큰을 URL 매개변수로 전달했는지 확인하는 의존성 함수 작성하기

from fastapi import FastAPI, Request, Depends, HTTPException
from fastapi.routing import APIRouter

app = FastAPI()

def check_token(token: str):
    if token != "my-secret-token":
        raise HTTPException(status_code=401, detail="Unauthorized")
    return token

router = APIRouter(dependencies=[Depends(check_token)])

# router에 라우트 추가
@router.get("/items")
def read_items_from_router():
    return {"message": "Access granted, you can view the items."}

@app.get("/public/")
def read_public():
    return {"message": "This is a public endpoint."}
    
# FastAPI 애플리케이션에 router 포함
app.include_router(router, prefix="/api")

- 토큰 없이 접근: 에러 메시지 출력

- 토큰을 포함하여 접근: 설정한 메시지 출력

- 공개 엔드포인트 접근: 설정한 메시지 출력

▶ APIRouter에 의존성을 설정하면, 해당 라우터에 등록된 엔드포인트는 의존성을 만족해야만 접근이 가능하게 된다.


APIRouter와 라우트 설정의 상속

 

FastAPI에서 APIRouter는 다른 APIRouter 또는 FastAPI 애플리케이션에 추가될 수 있으며, 이때 상위 라우터에서 설정한 옵션들을 하위 라우터에서 상속받을 수 있다. (주로 tags, dependencies 같은 설정)

이 기능을 중복 코드를 줄이고, 특정 설정을 여러 라우터에 쉽게 적용하도록 도와준다.

 

상속 기능은 하위 APIRouter가 상위 APIRouter 또는 FastAPI 애플리케이션에 포함될 때 상위 라우터의 설정을 그대로 물려받는 것을 의미한다.

from fastapi import FastAPI, Request, Depends, HTTPException, APIRouter

app = FastAPI()

# 공통 의존성 함수
def common_dependency():
    return "This is a common dependency"

# 상위 라우터
parent_router = APIRouter(
    prefix="/parent",
    tags=["parent"],
    dependencies=[Depends(common_dependency)]
)

@parent_router.get("/item")
def read_parent_item():
    return {"message": "This is an item from the parent router."}
    
# 하위 라우터
child_router = APIRouter()

@child_router.get("/item")
def read_child_item(common:str = Depends(common_dependency)):
    return {"message": "This is an item from child router", "common": common}

# 하위 라우터를 상위 라우터에 추가 (상속)
parent_router.include_router(child_router, prefix="/child")

# 상위 라우터를 애플리케이션에 추가
app.include_router(parent_router)

 

http://127.0.0.1:8000/parent/item

http://127.0.0.1:8000/parent/child/item

▶ 상위 라우터인 parent_router에서 설정한 의존성 함수 common_dependency 가 하위 라우터인 child_router에서도 동작하는 것을 확인할 수 있다.


APIRouter vs 플라스크 블루프린트

 

FastAPI의 APIRouter

  • FastAPI에서 여러 엔드포인트를 그룹화하고 관리하는 데 사용.
  • 특정 API 버전이나 기능에 대해 관련된 경로 그룹화.
  • include_router() 메서드를 통해 FastAPI 애플리케이션에 통합.

Flask의 Blueprint

  • Flask에서 여러 라우트, 템플릿, 정적 파일 등을 그룹화하여 모듈화.
  • 앱의 구조를 분리하여 기능 단위로 나눌 수 있다.
  • register_blueprint() 메서드를 통해 Flask 애플리케이션에 통합.

1. 코드 구조와 관리
FastAPI의 APIRouter

  • 비동기 프로그래밍을 지원하며, 타입 힌트를 통해 입력 및 출력 데이터 검증 자동화.
  • 성능이 뛰어나며, 더 많은 비동기 기능 지원.
  • APIRouter를 사용하려면 객체를 생성해야 한다.
from fastapi import APIRouter
router = APIRouter()
  • 애플리케이션에 APIRouter를 등록할 때는 include_router() 메소드 사용
app.include_router(router, prefix="/api/")

 

Flask의 Blueprint

  • 동기 방식으로 작동하며, 더 유연한 템플릿 엔진 지원.
  • Flask의 구조를 활용하여 URL 라우팅과 템플릿 렌더링을 쉽게 관리.
  • 사용하려면 블리프린트 객체 생성
from flask import Blueprint
blueprint = Blueprint('example', __name__)
  • 애플리케이션에 블루프린트를 등록할 때는register_blueprint() 메소드 사용
app.register_blueprint(blueprint, url_prefix="/api")

 

2. 확장성 및 유연성
APIRouter

  • FastAPI 특유의 강력한 데이터 검증 및 문서화 기능을 연동하여 사용.
  • 의존성 주입을 통한 코드 재사용성을 높일 수 있다.

Blueprint

  • Flask의 기본적인 기능을 활용하여 복잡한 애플리케이션 구조를 쉽게 유지관리.
  • Flask의 확장성을 통해 다양한 플러그인을 사용.

APIRouter는 dependencies와 middlewares를 지원하여 라우터 수준에서 의존성과 미들웨어를 적용할 수 있으나, 플라스크는 라우터 수준에서 의존성과 미들웨어를 적용할 수 없다.


[참고]

가장 빠른 풀스택을 위한 Flask & FastAPI


다음 내용

 

[파이썬] FastAPI - 쿼리 매개변수, 경로 매개변수, 백그라운드 태스크

이전 내용 [파이썬] FastAPI - 정적 파일, API Router이전 내용 [파이썬] FastAPI - FastAPI와 Jinja2 고급 문법시작에 앞서해당 내용은 , Dave Lee 지음. BJ Public 출판.내용을 토대로 작성되었습니다. 보다 자세한

puppy-foot-it.tistory.com

 

728x90
반응형