HTTP 파이

HTTP 요청을 생성하고 응답을 볼 수 있는 도구들을 다음과 같이 다양하다.

  • curl - terminal에서 사용
  • wget - terminal에서 사용
  • Postman 또는 Insomnia - UI 프로그램
  • HTTPPie
(fastapi) PS D:\workspace\fastapi> pip install httpie

FastAPI 앱을 실행하고, 다음을 실행하면 응답을 받을수 있다. 호스트가 localhost인 경우 호스트를 생략할 수 있다.

image


경로 매개변수 (path parameter)

경로 매개변수(Path Parameters)는 흔히 우리가 말하는 URL 경로에 들어가는 변수를 의미한다.

import uvicorn

from fastapi import FastAPI

app = FastAPI()

@app.get('/users/{user_id}')
def get_user(user_id):
    return {'user_id': user_id}

if __name__ == '__main__':
    uvicorn.run('main:app', reload=True)

이제 http://localhost:8000/users/123 을 호출하면,

(fastapi) PS D:\workspace> http :8000/users/123
HTTP/1.1 200 OK
content-length: 17
content-type: application/json
date: Sat, 13 Aug 2022 08:20:33 GMT      
server: uvicorn

{
    "user_id": "123"
}

문자열 123을 응답으로 받았다. 이처럼 http 통신은 타입 없이 전부 문자열로만 통신한다. 이 때 정수형 123을 응답으로 받고 싶으면 어떻게 해야 할까? 아래와 같이 타입 힌트를 추가해 주면 된다.

import uvicorn

from fastapi import FastAPI

app = FastAPI()

@app.get('/users/{user_id}')
def get_user(user_id: int):
    return {'user_id': user_id}

if __name__ == '__main__':
    uvicorn.run('main:app', reload=True)
(fastapi) PS D:\workspace> http :8000/users/123
HTTP/1.1 200 OK
content-length: 15
content-type: application/json
date: Sat, 13 Aug 2022 08:23:35 GMT      
server: uvicorn

{
    "user_id": 123
}

만약에 누가봐도 정수형이 아닌 user_id를 넘겨주었을 때는 어떻게 되는지 확인해보자.

(fastapi) PS D:\workspace> http :8000/users/dijlgijlkdjfw
HTTP/1.1 422 Unprocessable Entity
content-length: 104
content-type: application/json
date: Sat, 13 Aug 2022 08:25:15 GMT      
server: uvicorn

{
    "detail": [
        {
            "loc": [
                "path",
                "user_id"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

이렇게 어떤 부분이 오류인지 까지 알려주고 자동으로 에러 핸들링을 해준다.

swagger에서도 동일하게 확인해 볼 수 있다.

image


FastAPI 주의점 (순서 문제)

이번에는 현재 유저를 반환하는 앤드포인트를 추가해보겟다.

import uvicorn

from fastapi import FastAPI

app = FastAPI()  # fastapi app 인스턴스화 

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}

# 추가: 현재 유저를 반환하는 앤드포인트
@app.get("/users/me")
def get_current_user():
    return {"user_id": 123}

if __name__ == '__main__':
    uvicorn.run('main:app', reload=True)

이제 요청을 보내보자.

(fastapi) PS D:\workspace> http :8000/users/me
HTTP/1.1 422 Unprocessable Entity
content-length: 104
content-type: application/json
date: Sat, 13 Aug 2022 08:32:49 GMT
server: uvicorn

{
    "detail": [
        {
            "loc": [
                "path",
                "user_id"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

에러가 난다. 그 이유는 me 라는 user_id 가 들어 왓을 때 fastAPI는 코드 상에 위에서 아래로 실행하기 때문에 get_user(user_id: int)로 먼저 들어가 타입 에러를 내뱉기 때문이다. 이는 코드의 순서를 바꾸기만 하면 해결된다.

import uvicorn

from fastapi import FastAPI

app = FastAPI() 

# 추가: 현재 유저를 반환하는 앤드포인트
@app.get("/users/me")
def get_current_user():
    return {"user_id": 123}

@app.get("/users/{user_id}")
def get_user(user_id: int):
    return {"user_id": user_id}


if __name__ == '__main__':
    uvicorn.run('main:app', reload=True)
(fastapi) PS D:\workspace> http :8000/users/me
HTTP/1.1 200 OK
content-length: 15
content-type: application/json
date: Sat, 13 Aug 2022 08:34:43 GMT
server: uvicorn

{
    "user_id": 123
}

(참고) curl 명령어

curl 명령어 예시

$ curl [options] [URL...]

이 명령은 터미널 창에 example.com 홈페이지의 소스 코드를 인쇄한다.

$ curl example.com
  • -X: –request Specify request command to use
  • -H: –header HTTP Header에 에 추가. 위 예제에서는 Content-Type:application/json 과 Authorization: Bearer abcdbdg을 추가함
  • -d: –data HTTP POST data
  • –data-ascii HTTP POST ASCII data
  • –data-binary HTTP POST binary data
$ curl -X POST\
-H Content-Type:application/json\
-H Authorization: Bearer abcdbdg\
-d @data.json\