Flask | Basic Flask

gemma. K·2020년 12월 27일
0
post-thumbnail
post-custom-banner

flask

이번 브랜디 기업협업에서 flask를 이용해 브랜디 서비스와 어드민 페이지를 클론하기로 했다. 그 동안 가까웠던 django를 뒤로 하고 flask의 기초부터 다시 시작하기로 했다. 그래서 flask로 api 구현을 시작하기 전, flask의 몇 가지 특징에 대해 정리해 보고자 한다.

특징

1. 간단한 API 작성

flask는 flask 설치 후, app.py라는 파일을 생성한 후 간단한 코드로도 api를 구현할 수 있다.

from flask import Flask              - 1

app = Flask(__name__)                - 2

@app.route("/ping")                  - 3
def ping():                          - 4
    return "pong"
    
if __name__ = '__main__':            - 5
    app.run()
$ FLASK_APP=app.py FLASK_ENV=development FLASK_DEBUG=1 flask run - 6
  1. flask에서 Flask class를 가져온다. Flask class는 웹 어플리케이션 인스턴스를 만드는 프로토 타입 객체이다.
  2. __name__이라는 매개 변수를 가진 앱 인스턴스를 만들고 app변수에 담는다.
  3. 앱 라우터를 생성하고,/ping로 경로가 설정된다.
  4. 3번의 라우터가 호출되면 실행 될 함수
  5. __main__ 변수는 스크립트가 실행될 때, 이 스크립트에 이름을 할당한다. 스크립트 이름이 스크립트에 __name__라는 이름이 할당된 경우, 앱이 실행된다.
  6. flask run 명령어는 FLASK_APP 환경변수가 가리키는 파일 즉 앱이 어디 위치해 있는 지 알도록 하는 명령어이다.

FLASK_ENV: 기본값은 production. development는 디버그 모드를 활성화 시킨다.
FLASK_DEBUG: 디버그 모드는 스크립트들이 수정되어도 서버를 안정적으로 재구동 시키고 개발할 때, python 오류들을 터미널에서 볼 수 있어 개발자에게 유용하다.


2. Raw SQL Query

flask를 사용할 땐, 주로 ORM(Object-Relational-Mapping) 보다는 raw sql 쿼리를 사용한다. django orm에 매우 익숙해져 SELECT * FROM만 쓰던 나는 이제야 좀 더 본격적으로 sql문과 가까워지지 않을까 싶다.

sql(Structured Query Language)은 데이터베이스에 접속하여 데이터 읽기, 생성, 삭제, 수정 등에 기반이 되는 언어

3. Layered Architecture Patterns

레이어드 아키텍쳐란 코드를 논리적인 부분 혹은 역할에 따라 독립된 모듈로 나누어서 구성하는 패턴으로 각 모듈이 서로의 의존도에 따라 층층히 쌓듯이 연결되어서 전체의 시스템을 구현하는 구조다.

앞서 flask의 특징으로 언급한 간단한 api 구현 방식은 코드가 적을 수록 함께 개발하는 개발자가 적을 수록 긍정적인 요인이지만 현실 속 개발에서는 코드는 방대해 질 수 밖에 없고, 최소한 2명 이상의 개발자들과 함께 작업을 해야한다. 그러므로 각 모듈의 역할과 기능이 명확한 것이 더욱 편리하다. flask에는 다음 세 가지의 레이어가 존재한다.

  • presentation layer
  • business layer
  • persistence layer

Presentation Layer

사용자 혹은 클라이언트 시스템과 직접적으로 연결되는 부분으로 엔드포인트들을 정의 하고 호출된 endpoint와 method에 대한 요청을 읽는 역할을 담당한다.

Business Layer

비즈니스 로직을 구현하는 부분으로 Presentation Layer에서 읽어들인 호출에 대한 기능을 수행하는 역할을 한다.

Persistence Layer

데이터베이스와 가장 가까운 부분으로 비즈니스 레이어에서 필요한 데이터를 읽고, 생성하며 수정, 삭제 등을 수행한다.

4. 단방향 의존성

각 레이어는 각자의 역할이 명확, 독립적이고 단방향으로 의존한다는 특징이 있어서 presentation layer는 business layer에 의존하고, business layer는 persistence layer에 의존적이다. 회원가입 API는 다음 아래와 같이 구성된다.

Presentation Layer (View)

def create_endpoints(app, services):
    user_service = services.user_service
    
    @app.route("/sign-up", methods=['POST'])
    def sign_up():
        new_user = request.json
        new_user = user_service.create_new_user(new_user)
        
        return jsonify(new_user)

Presentation layer에서는 Business Layer(service)의 service class 내의 create_new_user 함수를 사용하여 새로운 유저를 생성한 뒤 new_user 객체를 json화 시켜 리턴한다.

Business Layer (Service)

class UserService:
    def __init__(self, user_dao, config):
        self.user_dao = user_dao
        
    def create_new_user(self, new_user):
        new_user['password'] = bcrypt.hashpw(
        	new_user['password'].encode('utf-8'),
            bcrypt.gensalt()
        )
        
        new_user_id = self.user_dao.insert_user(new_user)
        
        return new_user_id

create_new_user함수는 새로 생성하고자 하는 사용자의 패스워드를 암호화하고 Persistence Layer(model)의 user_dao 객체의 inser_user 함수를 활용하여 id(pk) 값을 얻고 이를 리턴한다.

Persistence Layer (Model)

class UserDao:
    def __init__(self, database):
        self.db = database
    
    def insert_user(self, user):
        return self.db.execute(text("""
            INSERT INTO users (
                name,
                email,
                profile,
                hashed_password
            ) VALUES (
                :name,
                :email,
                :profile,
                :password
            )
        """), user).lastrowid

Persistence Layer에서는 환경 변수 __init__을 통해 어떤 클래스의 객체가 만들어질 때 해당 객체의 성질을 결정한다. 함수 __init__은 database를 매개 변수를로 받아 self.db 값이 매개 변수 database를 향하도록 설정한다.

insert_user 함수는 user 객체를 매개 변수로 받아 db에 접속하여 users 테이블에 로우를 생성하고 동시에 그 로우의 id 값을 리턴한다.

post-custom-banner

0개의 댓글