이번 챕터의 모든 링크는 2019년 2월 25일의 코드 스냅샷 기준입니다. flask-restful을 아예 모른다면, Quickstart를 읽어보고 오는 것을 추천합니다.
flask-restful도 코드 베이스가 작은 편이 아니지만, 그 모두를 우리가 알 필요는 없다. 이번에는 Api
와 Resource
클래스라는, 다소 기초적인 내용을 다뤄 보겠다.
Resource
는 flask-restful을 구성하는 핵심 클래스 중 하나인데, 가장 먼저 눈에 띄는 부분은 MethodView
를 상속받아 dispatch_request
를 오버라이드했다는 것이다. flask_restful.Resource::dispatch_request
flask-restful이 오버라이드한 dispatch_request
메소드의 로직을 요약하자면,
self
에서 requested method에 해당하는 메소드를 가져오고, dispatch할 메소드가 발견되지 않는다면 assert
statement를 통해 AssertionError
를 raise한다.method_decorators
에 접근해서, dispatch할 메소드에 해당하는 데코레이터들을 가져와 적용한다. 메소드 이름을 key로, 데코레이터 함수로 이루어진 리스트를 value로 두는 딕셔너리라고 보면 된다.from functools import wraps
from flask_restful import Resource
def print_hello(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
print('hello')
return fn(*args, **kwargs)
return wrapper
class Dummy(Resource):
method_decorators = {
'get': [print_hello]
}
def get(self):
return 'hi!'
print_hello
메소드는 get 메소드에 대해 @print_hello
형태로 데코레이션되지 않았으나, method_decorators
에 정의되어 있으므로 dispatch_request
에 의해 런타임에 데코레이션이 적용된다.MethodView
에서 지원하는 decorators
개념을 메소드 단위로 쪼개서 적용할 수 있도록 지원하기 위함이다.ResponseBase
라면 바로 리턴, 그게 아니라면 representation
을 가지고 mimetype(Content-Type 헤더의 값)을 새로 산정한다. flask-restful에서 이야기하는 representation이라는 개념은 조금 복잡하며, 이를 이해하는 것은 flask-restful의 코드 리딩에 매우 큰 도움을 주기에 따로 글을 쓸 것이다. 여기서 간단히 말하면 class attribute인 representations
와 요청의 Accept 헤더를 가지고 best match(가장 써볼만한 mimetype)를 가져오고, 이게 없으면 그냥 리턴해서 Api
객체의 생성자에 전달된 default_mediatype
을 따른다. flask-restful을 써먹는 걸 보면 대부분 후자의 로직을 타게 된다. default_mediatype
의 기본값은 application/json
이며 이에 대응되는 JSON serializer를 flask-restful이 미리 준비(flask_restful.representations.json.py::output_json)해 두어서, 따로 뭔가 설정하지 않으면 대충 JSON으로 적절히 response된다.MethodView
를 사용하던 것처럼, 해당 클래스를 상속받아 리소스를 정의하는 것이 가장 기본적인 practice다.
from flask_restful import Resource
class Dummy(Resource):
def get(self):
return {'hello': 'world'}
위에서 말했던 것처럼, default_mediatype
과 이에 대응되어 있는 serializer 함수에 따라 Dummy::get
메소드의 반환값이 JSON string으로 dump된다. 일단 당장 편한 부분은, jsonify
함수로 감싸줄 필요가 없다는 것이다.
일반적인 Flask extension 라이브러리들과 같이, 위에서 얘기했던 default_mediatype
처럼 해당 extension에 대한 메타데이터들을 정리하고 이에 의존되는 메소드들을 정의해 두고 있다. Flask
의 인스턴스와 extension의 요소들을 중간에서 엮어주는 역할이다. Api::add_resource
메소드를 통해 Resource
의 서브클래스로서 정의된 view 핸들러를 라우팅하는 것이 핵심 기능이다. 맨 아래의 예제에 포함되어 있다.
Resource
와 Api
클래스만 알고 있으면 flask-restful은 이미 60% 이상 알고 있다고 보면 된다. 아래는 Resource와 Api만을 사용하는 flask-restful의 기초적인 사용 사례다.
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class Dummy(Resource):
def get(self):
return {'hello': 'world'}
api.add_resource(Dummy, '/', '/index')
if __name__ == '__main__':
app.run()
오