1. Flask와 Flask-RESTX

nine·2022년 7월 29일
0

1-1. Flask-RESTX


 프로젝트에서 Flask를 사용해 개발하고자 했던 것은 웹 애플리케이션이 아니라 API 서버이다. 물론 일반 Flask를 사용해서도 API서버를 만들 수 있지만 Flask-RESTX Extension을 사용하면 보다 직관적으로 API서버를 작성할 수 있고, 도움이 되는 기능들을 추가로 사용할 수 있게 된다. 특히, 추후에 소개할 swagger와 같은 기능을 추가적인 Extension설치 없이 제공하기 때문에 Flask-RESTX를 사용해 프로젝트를 진행하였다.

설치

pip install Flask
pip install flask-restx

 

1-2. Flask vs. Flask-RESTX


 이제 직접 예시를 작성해 보면서 Flask를 사용했을 때의 코드와 Flask-RESTX를 사용했을 때의 코드를 비교해 보도록 하겠다. 먼저 예시 프로젝트의 구조는 다음과 같다.

app
 │  app_flask.py
 │  app_flask_restx.py
 │
 └─hello
     │  hello_flask.py
     │  hello_flask_restx.py

app_flask.pyhello_flask.pyFlask로 작성된 예시 프로젝트이고, app_flask_restx.pyhello_flask_restx.pyFlask_RESTX로 작성된 예시이다.

Flask

 
app_flask.py

from flask import Flask
from hello import hello_flask

app = Flask(__name__)

app.register_blueprint(hello_flask.bp) #블루프린트 등록

if __name__ == "__main__":
    app.run()

 
hello_flask.py

from flask import Blueprint, jsonify, make_response

bp = Blueprint('hello_flask', __name__, url_prefix='/hello_flask')

@bp.route("", methods=['GET'])
def hello():
    response = {"message" : "hello"}
    return make_response(jsonify(response), 200)

 원래 이런 예시정도의 애플리케이션은 모듈화를 하지 않아도 되지만 추후에 리뷰할 캡스톤 프로젝트는 모듈화가 되어 있으므로 이에 대해 이해하기 쉽도록 Flask의 모듈화에 대해서 정리하고 간다.
 BlueprintFlask에서 모듈화를 위해 지원하는 기능이다. 이 예시같은 작은 프로젝트는 하나의 파일로 작성하여도 가독성이나 유지 보수 측면에서 문제가 발생하지 않으나, 실제 프로젝트는 이렇게 단순하지가 않기 때문에 모듈 단위로 분리하여 개발한다.
 Blueprint()를 통해서 Blueprint객체를 생성한다. 첫 번째 인자인 'hello_flask'는 이 Blueprint객체의 이름이다. 세 번째 인자인 url_prefix='/hello_flask'는 아래의 @bp.route()를 통해 연결될 url의 접두어를 등록한 것이다.
 @bp.route()을 통해서 해당 url을 통해 아래의 hello함수를 호출할 수 있게 된다. 즉 http://BASE_URL/hello_flask를 통해 접근하면 hello함수의 실행 결과를 얻을 수 있는 것이라고 생각하면 된다. 두 번째 인자 methods=['GET']은 HTTP의 method 중 GET method로 해당 url에 접근했을 때 아래의 함수를 매핑해준다는 것이다. HTTP의 method는 이외에도 'POST', 'PUT', 'DELETE'등이 있지만 여기서는 더 이상 언급하지 않는다.
  def hello()는 사용자에게 {"message" : "hello"}라는 JSON응답과 HTTP status code 200을 반환한다. 이를 위해서 우선 response란 변수에 {"message" : "hello"}라는 Dictionary자료형을 저장한다. 그 다음 response를 JSON응답으로 변환하기 위해 jsonify()함수를 사용한다. 마지막으로 응답에 status code를 추가하기 위해 make_response()함수를 사용한다.

 실제로 애플리케이션이 잘 동작하는지를 확인하기 위해 Postman을 사용해서 테스트해본다.

이 사진은 Flask앱을 실행했을 때 터미널을 캡쳐한 것인데 맨 아래를 보면 해당 서버가 http://127.0.0.1:5000/에서 동작한다는 것을 알 수 있다. 여기에 아까 지정한 url_prefix를 더해서 최종적으로 http://127.0.0.1:5000/hello_flask 라는 url에 postman을 사용해 GET 요청을 보내 보았다.

정상적으로 JSON응답이 반환되는 것을 확인할 수 있다. 그렇다면 Flask-RESTX를 사용해서 이를 작성하면 어떻게 될까?

Flask-RESTX

 
app_flask_restx.py

from flask import Flask
from flask_restx import Api
from hello.hello_flask_restx import Hello_Flask_Restx

app = Flask(__name__)

api = Api(app)

api.add_namespace(Hello_Flask_Restx, '/hello_flask_restx')

if __name__ == "__main__":
    app.run()

 
hello_flask_restx.py

from flask_restx import Namespace, Resource

Hello_Flask_Restx = Namespace('hello_flask_restx')

@Hello_Flask_Restx.route('')
class Hello(Resource):
    def get(self):
        return {"message" : "hello"}, 200

 Flask-RESTX에서는 Blueprint대신 Namespace를 통해서 모듈화를 제공한다. Flask객체를 감싼 Api객체를 통해 Namespace를 등록할 수 있다. add_namespace()함수를 통해 등록하는데, 앞의 Blueprint와 달리 이 add_namespace()함수에서 url_prefix를 등록한다. 여기서는 두 번째 인자인 '/hello_flask_restx'를 말한다.
 @Hello_Flask_Restx.route()를 통해서 url과 함수를 매핑하는데, 여기서 일반 Flask와 차이가 생긴다. 원래는 route()함수의 인자로써 매핑되는 경로와 method를 지정해 주었는데, Flask-RESTX는 Resource객체를 상속하는 class를 만들고 해당 class 내에 method함수를 override하는 것으로 매핑한다. 이 코드에서는 get()을 override했으므로 get요청에 대해 처리하는 로직을 작성한 것이다.
JSON응답과 HTTP status code를 반환하는 것도 간단하다. jsonify()를 사용할 필요도 없이 Dictionary 객체 그대로 return하면 된다. status code도 동일하게 반환하고자 하는 status code를 ,로 구분하여 작성하면 된다.

실행 결과도 완전히 같다.

Flask-RESTX를 선택했던 이유?

 그 때 당시에는 진짜로 이런 웹 프레임워크를 처음 접하다 보니까 HTTP 통신, JSON, 이러한 기본 개념들이 전혀 잡혀 있지 않았었기 때문에 Flask-RESTX가 좀 더 직관적으로 느껴졌다. 미리 공부하고 개발에 들어간 것이 아니라 공부하면서 개발에 들어갔었기 때문에 보다 직관적이고 응답 등을 쉽게 커스텀할 수 있는 Flask-RESTX가 더 매력적이었고, 해당 Extension을 선택할 때는 알지 못했지만 이후 협업 과정을 위해 API 문서를 작성해야 했는데, 이 때 Flask-RESTX를 선택한 것이 큰 도움이 되었다.

0개의 댓글