Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from JoMingyu/issue/4
Flask Large Application Example 적용
- Loading branch information
Showing
21 changed files
with
169 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from flask import Flask | ||
from werkzeug.exceptions import HTTPException | ||
|
||
from app.misc.log import log | ||
|
||
|
||
def register_extensions(flask_app: Flask): | ||
pass | ||
|
||
|
||
def register_views(flask_app: Flask): | ||
from app.views import route | ||
|
||
route(flask_app) | ||
|
||
|
||
def register_hooks(flask_app: Flask): | ||
from app.hooks.error import broad_exception_handler, http_exception_handler | ||
from app.hooks.request_context import after_request | ||
|
||
flask_app.after_request(after_request) | ||
flask_app.register_error_handler(HTTPException, http_exception_handler) | ||
flask_app.register_error_handler(Exception, broad_exception_handler) | ||
|
||
|
||
def create_app(*config_cls) -> Flask: | ||
log(message='Flask application initialized with {}'.format(', '.join([config.__name__ for config in config_cls])), | ||
keyword='INFO') | ||
|
||
flask_app = Flask(__name__) | ||
|
||
for config in config_cls: | ||
flask_app.config.from_object(config) | ||
|
||
register_extensions(flask_app) | ||
register_views(flask_app) | ||
register_hooks(flask_app) | ||
|
||
return flask_app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from flask import current_app, request | ||
|
||
|
||
class _ContextProperty: | ||
@property | ||
def secret_key(self) -> str: | ||
return current_app.secret_key | ||
|
||
@property | ||
def user_agent(self) -> str: | ||
return request.headers['user_agent'] | ||
|
||
@property | ||
def remote_addr(self) -> str: | ||
return request.remote_addr | ||
|
||
|
||
context_property = _ContextProperty() |
Empty file.
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from werkzeug.exceptions import HTTPException | ||
|
||
|
||
def http_exception_handler(e: HTTPException): | ||
return '', e.code | ||
|
||
|
||
def broad_exception_handler(e: Exception): | ||
return '', 500 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from flask import Response | ||
|
||
|
||
def after_request(response: Response) -> Response: | ||
try: | ||
response.headers['X-Content-Type-Options'] = 'nosniff' | ||
response.headers['X-Frame-Options'] = 'deny' | ||
finally: | ||
return response |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from termcolor import colored | ||
|
||
|
||
def log(message: str, keyword: str="WARN"): | ||
if keyword == "WARN": | ||
print(colored('[WARN]', 'yellow'), message) | ||
elif keyword == "ERROR": | ||
print(colored('[ERROR] ' + message, 'red')) | ||
elif keyword == "INFO": | ||
print(colored('[INFO]', 'blue'), message) | ||
else: | ||
print(colored('[{}]'.format(type), 'cyan'), message) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from flask import Blueprint, Flask | ||
from flask_restful import Api | ||
|
||
|
||
def route(flask_app: Flask): | ||
from app.views.sample import sample | ||
|
||
handle_exception_func = flask_app.handle_exception | ||
handle_user_exception_func = flask_app.handle_user_exception | ||
# register_blueprint 시 defer되었던 함수들이 호출되며, flask-restful.Api._init_app()이 호출되는데 | ||
# 해당 메소드가 app 객체의 에러 핸들러를 오버라이딩해서, 별도로 적용한 handler의 HTTPException 관련 로직이 동작하지 않음 | ||
# 따라서 두 함수를 임시 저장해 두고, register_blueprint 이후 함수를 재할당하도록 함 | ||
|
||
# - blueprint, api object initialize | ||
api_v1_blueprint = Blueprint('api_v1', __name__, url_prefix='/api/v1') | ||
api_v1 = Api(api_v1_blueprint) | ||
|
||
# - route | ||
api_v1.add_resource(sample.Sample, '/sample') | ||
|
||
# - register blueprint | ||
flask_app.register_blueprint(api_v1_blueprint) | ||
|
||
flask_app.handle_exception = handle_exception_func | ||
flask_app.handle_user_exception = handle_user_exception_func |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import arrow | ||
from flask_restful import Resource | ||
|
||
|
||
class BaseResource(Resource): | ||
def __init__(self): | ||
self.utcnow = arrow.utcnow() | ||
self.kstnow = self.utcnow.to('Asia/Seoul') | ||
self.iso8601_formatted_utcnow = self.utcnow.isoformat() | ||
self.iso8601_formatted_kstnow = self.kstnow.isoformat() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from flask import request | ||
|
||
from app.views.base import BaseResource | ||
|
||
|
||
class Sample(BaseResource): | ||
def post(self): | ||
payload = request.json | ||
|
||
return payload, 201 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import os | ||
|
||
|
||
class LocalLevelConfig: | ||
SECRET_KEY = os.getenv('SECRET_KEY', '85c145a16bd6f6e1f3e104ca78c6a102') | ||
|
||
|
||
class ProductionLevelConfig: | ||
SECRET_KEY = os.getenv('SECRET_KEY') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class LocalDBConfig: | ||
pass | ||
|
||
|
||
class RemoteDBConfig: | ||
pass |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
RUN_SETTING = { | ||
'host': 'localhost', | ||
'port': 5000, | ||
'debug': True, | ||
'threaded': True | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import os | ||
|
||
from app import create_app | ||
from config.app_config import ProductionLevelConfig | ||
from config.db_config import RemoteDBConfig | ||
|
||
if 'SECRET_KEY' not in os.environ: | ||
raise Warning('The secret key must be passed by the <SECRET_KEY> envvar.') | ||
|
||
application = create_app(ProductionLevelConfig, RemoteDBConfig) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,9 @@ | ||
from flask import Flask | ||
|
||
app = Flask(__name__) | ||
|
||
|
||
@app.route('/') | ||
def index(): | ||
return 'This is version 2' | ||
from app import create_app | ||
from config.app_config import LocalLevelConfig | ||
from config.db_config import LocalDBConfig | ||
from constants.local_run import RUN_SETTING | ||
|
||
app = create_app(LocalLevelConfig, LocalDBConfig) | ||
|
||
if __name__ == '__main__': | ||
app.run() | ||
app.run(**RUN_SETTING) |