본문 바로가기

개발하자

FastAPI에서 동일한 앱에서 다른 API를 호출하는 방법은 무엇입니까?

반응형

FastAPI에서 동일한 앱에서 다른 API를 호출하는 방법은 무엇입니까?

(SO에서 다음과 같은 질문을 찾았지만 도움이 되지 않았습니다.)

나는 Fastapi를 사용하여 다음과 같은 폴더 구조로 앱을 만들고 있다

enter image description here

앱의 진입점이다

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from app.api.v1 import lines, upload
from app.core.config import settings

app = FastAPI(
    title=settings.PROJECT_NAME,
    version=0.1,
    openapi_url=f'{settings.API_V1_STR}/openapi.json',
    root_path=settings.ROOT_PATH
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.BACKEND_CORS_ORIGINS,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(upload.router, prefix=settings.API_V1_STR)
app.include_router(lines.router, prefix=settings.API_V1_STR)

에 GET 엔드포인트가 2개 있습니다:

  • --> 파일에서 임의 행을 반환합니다
  • --> 의 출력을 반환해야 합니다

두 번째 GET 엔드포인트의 출력은 첫 번째 GET 엔드포인트의 출력의 문자열과 반대여야 하므로 다음 단계를 수행하려고 했습니다

코드:

import random

from fastapi import APIRouter, Request
from starlette.responses import RedirectResponse

router = APIRouter(
    prefix="/get-info",
    tags=["Get Information"],
    responses={
        200: {'description': 'Success'},
        400: {'description': 'Bad Request'},
        403: {'description': 'Forbidden'},
        500: {'description': 'Internal Server Error'}
    }
)


@router.get('/one-random-line')
def get_one_random_line(request: Request):
    lines = open('netflix_list.txt').read().splitlines()
    if request.headers.get('accept') in ['application/json', 'application/xml']:
        random_line = random.choice(lines)
    else:
        random_line = 'This is an example'
    return {'line': random_line}


@router.get('/one-random-line-backwards')
def get_one_random_line_backwards():
    url = router.url_path_for('get_one_random_line')
    response = RedirectResponse(url=url)
    return {'message': response[::-1]}

이렇게 하면 다음과 같은 오류가 발생합니다:

TypeError: 'RedirectResponse' object is not subscriptable

두 번째 GET 끝점의 를 로 변경하면 다음과 같은 출력이 나타납니다

enter image description here

내가 하는 실수가 뭐지?

예:

엔드포인트의 출력이 'Maverick'인 경우 의 출력은 'kcirevam'이어야 합니다




코드를 리팩터해서 공통 부품을 호출하는 기능으로 사용합니다. 일반적으로 컨트롤러 외부의 모듈에 이 기능이 있습니다.

# this function could live as LineService.get_random_line for example
# its responsibility is to fetch a random line from a file
def get_random_line(path="netflix_list.txt"):
    lines = open(path).read().splitlines()
    return random.choice(lines)


# this function encodes the rule that "if the accepted response is json or xml
# we do the random value, otherwise we return a default value"
def get_random_or_default_line_for_accept_value(accept, path="netflix_list.txt", default_value="This is an example"):
    if accept not in ("application/json", "application/xml"):
        return default_value

    return get_random_line(path=path)


@router.get('/one-random-line')
def get_one_random_line(request: Request):
    return {
        "line": get_random_or_default_line_for_accept_value(
            accept=request.headers.get('accept'),
        ),
    }


@router.get('/one-random-line-backwards')
def get_one_random_line_backwards(request: Request):
    return {
        "line": get_random_or_default_line_for_accept_value(
            accept=request.headers.get('accept'),
        )[::-1],
    }



당신은 당신의 코드에서 임의의 엔드포인트를 함수 호출로 직접 호출할 수 있고, 당신은 처리하거나 할 필요가 없다. 다음은 이 기능이 현재 상태로 실행되고 실행되는 방법에 대한 예입니다:

from fastapi import FastAPI, Request

app = FastAPI()


@app.get("/one-random-line")
async def get_one_random_line(request: Request):
    # implement your own logic here, this will only return a static line
    return {"line": "This is an example"}


@app.get("/one-random-line-backwards")
async def get_one_random_line_backwards(request: Request):
    # You don't have to do fancy http stuff, just call your endpoint:
    one_line = await get_one_random_line(request)
    return {"line": one_line["line"][::-1]}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=8000)

사용하면 다음과 같은 결과를 얻을 수 있습니다:

% curl localhost:8000/one-random-line          
{"line":"This is an example"}%     
% curl localhost:8000/one-random-line-backwards
{"line":"elpmaxe na si sihT"}%  



실제로 이 API의 다른 엔드포인트에서 API 엔드포인트를 호출할 수 있습니다. 다른 스레드에서 호출하면 됩니다. 따라서 통화를 위한 함수를 만들고 엔드포인트 내부에서 다음과 같은 것을 사용합니다:

thread = threading.Thread(target=request_foo, args=(arg1, arg2))
thread.start()

나쁜 관행이란 걸 알아둬요. 외부 파일에 공유 코드를 만들어 원하는 엔드포인트에서 사용하는 것이 좋습니다.


반응형