❓flask 구조 이해하기

yeeun lee·2020년 5월 28일
8

flask

목록 보기
4/5

해당 게시물은 깔끔한 파이썬 탄탄한 백엔드(송은우 저)의 내용 + pysql을 구글링하여 정리한 것이다. 아래 내용을 바탕으로 생각했을 때, flask 초기세팅 작업 순서는 다음대로 하면 될 것 같다.

  1. config.py
  2. model
  3. service
  4. view
  5. app.py
  6. run.py - django의 manage.py 기능을 하는 파일 생성. 이름은 마음 대로 !

1. 레이어드 아키텍처 패턴이란?

Layered architecture pattern, multi-tier architecture pattern이라고도 불린다. 코드를 논리적인 부분 혹은 역할에 따라 독립되 모듈로 나누어서 구성하는 패턴이다.

각 모듈은 서로 의존도에 따라 층층이 쌓듯이 연결되어 전체 시스템을 구현한다. 시스템마다 경우가 다르지만 보통 3개의 레이어가 존재한다.

1.1 구성 요소

- Presentation layer

시스템 사용자, 클라이언트 시스템과 직접 연결되는 부분. 웹사이트에서는 UI에 해당하고 백엔드는 엔드포인트 부분에 해당한다. 여기에서는 두 가지 로직을 구현한다.

  • API endpoint 정의한다.
  • 전송된 HTTP request를 읽어들인다.

- Business layer

비즈니스 로직을 구현하는 부분이다. 시스템이 구현하는 로직을 이 레이어에서 구현한다. 예를 들어 사용자가 전송하는 메시지가 300자를 넘을 경우, 이를 확인해 초과할 경우 거부하는 로직을 짜는 곳이다.

- Persistence layer

데이터베이스와 관련된 로직을 구현하는 부분이다. business layer에서 필요한 데이터 생성, 수정, 읽기를 처리해 데이터베이스에서 데이터를 저장, 수정, 읽어들이기를 하는 역할을 한다.

1.2 레이어드 아키텍처의 핵심 요소

- 단방향 의존성

presentation layer > business layer > persistence layer 방향으로 의존한다. 그리고 반대 방향은 완전히 독립적이다.

즉, persistence layer는 business, presentaion에 독립적이고 business는 presentation에 독립적이다.

- separation of concerns

각 레이어의 역할이 명확하다. presentaion layer는 비즈니스 로직을 전혀 구현하지 않고 business layer의 코드를 호출해서 사용해야 한다. business layer도 데이터베이스 처리를 하기 위해 persistence layer의 코드를 사용한다.

장점은

  • 코드의 확장성이 높아진다.
  • 역할이 명확해 가독성이 높아진다
  • 재사용 가능성도 높아진다. ex) business layer는 여러 다른 presentation layer에 적용될 수 있다.
  • 테스트 코드를 구현하기 수월해진다.

단점은... 초보자인 나로서는 역할 별로 파일이 너무 분산되어 있어서 한 번에 이해하기 어렵고 변수 관리하는 것이 빡세다 😟

2. 레이어드 아키텍처 적용

api
|- view : presentation layer - endpoint 정의, request 받기
|- service : business layer - 로직 구현
|- model : persistence layer - 데이터베이스 접속
|- app.py : 앱을 실행해 모든 레이어의 변수들을 연결해주는 기능

2.1 디렉토리 구성

- view

test endpoint를 하나 만들어 보자. 테이블은 아래와 같이 생겼다. id는 auto_increment 설정이 되어 있는 pk여서 user column만 post해주면 되는 상황이다.

mysql> select * from seller_keys;
+----+-------+
| id | user  |
+----+-------+
|  5 | yeeun |
|  6 | yeeun |
|  8 | yeeun |
+----+-------+

view는 service에 의존적이기 때문에 아래 코드에서 create_endpoint 인자 중 app은 app.py에서 정의한 Flask객체app = Flask(__name__)이고, services는 service의 user_serive에서 받을 로직 부분이다. (변수가 services.user_service인 이유는 app.py에서 Service 객체의 이름을 정의해주었기 때문이다)

하는 일은

  • 데코레이터로 endpoint 정의 (url, method)
  • http request에 필요한 input data 받기
  • business layer(service 코드)를 호출해 비즈니스 로직을 실행
  • 결과값을 받아 http response를 return 하기 (그냥 200만 보내도 됨)
from flask import request, jsonify
from model.user_dao import UserDao
from service.user_service import UserService

def create_endpoints(app, services):
    user_service  = services.user_service

    @app.route("/test", methods=['POST'])
    def sign_up():
        try:
            user = request.json
            user = user_service.create_new_user(user)
            return jsonify({'message':'ok'}), 200
        except Exception as e :
            return {'error': str(e)}

- service

로직을 담당하는 곳. 로직을 크게 나누어 클래스로 만든다. 예를 들어 내가 만들 서비스가 크게 user, product로 구분된다면 그와 관련된 클래스를 생성해 관련 기능을 모두 함수로 만드는 식이다.

service는 model에 의존적이기 때문에 함수의 파라미터로 model의 user_dao를 넣어준다.

from model.user_dao import UserDao

class UserService: 
    def __init__(self, user_dao, config):
        self.user_dao = user_dao 
        self.config = config
        
    def create_new_user(self, new_user):      
        user = self.user_dao.insert_user(new_user)  
        return user

- model

dabatabse는 pymysql을 통해 데이터베이스에 직접 접속해서, 원하는 값을 입력하거나 찾아서 리턴하는 방식으로 만들어진다.

  • DAO : database access object 데이터 접속을 담당하는 객체. dao 객체들을 통해 데이터베이스를 처리한다.
import json
import pymysql

class UserDao:

    def __init__(self, database): 
        self.db = database

    def insert_user(self, user):
        cursor = self.db.cursor()
        sql = """
                insert into seller_keys(
                user
                ) values (
                %s
                )
                """
        cursor.execute(sql, (user['user']))
        self.db.commit()
        self.db.close()

- app.py

각 레이어를 이어주는 역할을 한다. 레이어의 클래스나 모듈을 임포트해서 연결시켜주고, Flask 애플리케이션을 생성해주는 역할을 한다.

import pymysql
from flask import Flask
from model.user_dao import UserDao
from service.user_service import UserService
from view import create_endpoints

class Services:
    pass 

def create_app(test_config = None):
    
    app = Flask(__name__)
    app.debug = True

    if test_config is None:
        app.config.from_pyfile("config.py")
    else:
        app.config.update(test_config)
    
    database = pymysql.connect(host='localhost', 
    		               user='root', 
                               password='', 
                               db='brandi', 
                               charset='utf8'
                               )

    user_dao = UserDao(database)

    services = Services
    services.user_service = UserService(user_dao, app.config)

    user_service = UserService(user_dao, app.config)

    create_endpoints(app, services)

    return app
profile
이사간 블로그: yenilee.github.io

2개의 댓글

comment-user-thumbnail
2020년 10월 3일

정리하셨었군요 예은님~ ㅋㅋ

답글 달기
comment-user-thumbnail
2020년 12월 18일

잘 정리된 글 잘 읽고 갑니다! 감사합니다

답글 달기