이번 시간에는 Flask로 간단히 REST API를 주고 받는 API Server를 만들어 보겠습니다.
Flask는 Python 기반의 Micro Web Framework 입니다. 배우기 쉽고, 간단한 코드 구현과 자유도가 높다는 점이 장점입니다.
자유도가 높은 만큼, 간단한 코드 구현을 권장합니다.
Flask는 현실적으로 서버의 Application단을 구현 한다기 보단 API Server의 역할을 더 많이 합니다. 애초에 이 친구는 Micro Web Framework 입니다. 미니멀리즘을 표방하고 나온 친구죠. 그래서 사람들이 Flask로 API Server를 구현 하고, 이를 Docker나 Kubernetes를 이용해 스케쥴링을 하며 서버 자원을 유연하게 활용 하는 경우가 많습니다.
즉, 요약해보면 장점은 세 가지 입니다.
flask
와 Flask의 Extension인 flask-restx
pip
을 이용하여 설치합니다.
$ pip install flask
$ pip install flask-restx
다음 코드를 통해서 첫 번째 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 요청이 된 모습.
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으로 파라미터를 인식, 값이 잘 들어간 것을 볼 수 있습니다.
반환 하고자 하는 리턴 값으로 iterable 하게 값을 넣으면 됩니다. 순서는 다음과 같습니다.
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
멤버 함수를 오버라이딩 하여 구현 해 주면 됩니다. 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로 쉽게 해결 할 수 있습니다. 다음 시간에는 파일 분리와, 문서화에 대해서 알아 보도록 하겠습니다!