Flask로 REST API 구현하기 - 1. Flask-RESTX
Flask로 쉽게 REST API 만들기 2020-07-06

이번 시간에는 Flask로 간단히 REST API를 주고 받는 API Server를 만들어 보겠습니다.

Flask란?

FlaskPython 기반의 Micro Web Framework 입니다. 배우기 쉽고, 간단한 코드 구현과 자유도가 높다는 점이 장점입니다.

자유도가 높은 만큼, 간단한 코드 구현을 권장합니다.

왜 Flask로 API Server를 구현하나요?

Flask는 현실적으로 서버의 Application단을 구현 한다기 보단 API Server의 역할을 더 많이 합니다. 애초에 이 친구는 Micro Web Framework 입니다. 미니멀리즘을 표방하고 나온 친구죠. 그래서 사람들이 FlaskAPI Server를 구현 하고, 이를 DockerKubernetes를 이용해 스케쥴링을 하며 서버 자원을 유연하게 활용 하는 경우가 많습니다.

즉, 요약해보면 장점은 세 가지 입니다.

  1. API Server가볍게 구현 할 수 있습니다.
  2. DockerKubernetes를 이용해 여러 개의 컨테이너를 이용하여 스케쥴링이 용이 합니다.
  3. 일단 쉽고, 코드가 짧습니다. (매우 중요)

Installation

flaskFlaskExtensionflask-restx pip을 이용하여 설치합니다.

$ pip install flask
$ pip install flask-restx

첫 번째 Flask Server

다음 코드를 통해서 첫 번째 Flask Server를 만들어 보겠습니다.

app.py

from flask import Flask  # 서버 구현을 위한 Flask 객체 import
from flask_restx import Api, Resource  # Api 구현을 위한 Api 객체 import

app = Flask(__name__)  # Flask 객체 선언, 파라미터로 어플리케이션 패키지의 이름을 넣어줌.
api = Api(app)  # Flask 객체에 Api 객체 등록


@api.route('/hello')  # 데코레이터 이용, '/hello' 경로에 클래스 등록
class HelloWorld(Resource):
    def get(self):  # GET 요청시 리턴 값에 해당 하는 dict를 JSON 형태로 반환
        return {"hello": "world!"}

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)

그 다음 터미널에서 실행시켜 봅니다.

python app.py

그리고 'http://localhost/hello' 에 들어가 봅시다. 저는 구글 크롬의 확장 앱인, Advanced REST client를 이용하여 테스트 했습니다.

실행 결과는 다음과 같습니다. (저 같은 경우는 구름 IDE 환경에서 실행하여, 구름 IDE에서 제공하는 도메인으로 서버에 접속 하였습니다.)

정상적으로 API 요청이 된 모습.

다양한 Resourceful Routing

route의 url에 query string이 아닌 url pattern을 이용할 수 있습니다. url 자체에 변수를 삽입하는 방법으로 가능 하며, <타입명:변수명> 형태로 작성하면 됩니다. 그 변수는 class의 멤버 함수의 파라미터로 삽입하여 사용 합니다.

app.py

from flask import Flask
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)


@api.route('/hello/<string:name>')  # url pattern으로 name 설정
class Hello(Resource):
    def get(self, name):  # 멤버 함수의 파라미터로 name 설정
        return {"message" : "Welcome, %s!" % name}
    
if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)

url pattern으로 파라미터를 인식, 값이 잘 들어간 것을 볼 수 있습니다.

Status Code와 Header 설정

반환 하고자 하는 리턴 값으로 iterable 하게 값을 넣으면 됩니다. 순서는 다음과 같습니다.

  1. 반환 하고자 하는 dict 객체
  2. 반환 하고자 하는 Status Code
  3. 반환 하고자 하는 Header

app.py

from flask import Flask
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)


@api.route('/hello/<string:name>')
class Hello(Resource):
    def get(self, name):
        return {"message" : "Welcome, %s!" % name}
    
if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)

Status Code와 Header값이 잘 들어간 것을 확인 할 수 있습니다.

GET, POST, PUT, DELETE

GET, POST, PUT, DELETE 방식을 처리하는 방법은 단순합니다. get, post, put, delete 멤버 함수를 오버라이딩 하여 구현 해 주면 됩니다. body에 있는 데이터를 가져오기 위해서, 취하는 방법은 간단합니다. flask 모듈 내의 request 내의 json 객체를 이용하여, request body로 들어온 json값을 파싱하면 됩니다. json 객체는 dict 객체 입니다.

from flask import Flask, request
from flask_restx import Resource, Api

app = Flask(__name__)
api = Api(app)

todos = {}
count = 1

@api.route('/todos')
class TodoPost(Resource):
    def post(self):
        global count
        global todos
        
        idx = count
        count += 1
        todos[idx] = request.json.get('data')
        
        return {
            'todo_id': idx,
            'data': todos[idx]
        }


@api.route('/todos/<int:todo_id>')
class TodoSimple(Resource):
    def get(self, todo_id):
        return {
            'todo_id': todo_id,
            'data': todos[todo_id]
        }

    def put(self, todo_id):
        todos[todo_id] = request.json.get('data')
        return {
            'todo_id': todo_id,
            'data': todos[todo_id]
        }
    
    def delete(self, todo_id):
        del todos[todo_id]
        return {
            "delete" : "success"
        }

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=80)

POST 요청

GET 요청

PUT 요청

마치며

만약 우리가 한 10개 이상의 REST API를 구현 해야 한다면 어떻게 해야 할까요? 파일 분리는? API의 문서화는? 상당히 피곤 한 주제이지만, Flask-RESTX로 쉽게 해결 할 수 있습니다. 다음 시간에는 파일 분리와, 문서화에 대해서 알아 보도록 하겠습니다!