본문 바로가기

Python

MySQL과 Flask API를 연동하기

이전 포스팅인 Flask를 설치하고 간단한 API만들기에서는 Flask를 설치하고 간단한 서버를 띄우는 작업을 했습니다. 전에 만들었던 회원가입 API에서 불편한 점은 API가 새로 재시작될 때 마다 모든 데이터가 없어진다는 것 입니다. 데이터를 저장하기 위해서는 데이터베이스 시스템을 사용해야합니다. 이번에는 1장에서 만들었던 간단한 회원가입 API에 MySQL 데이터 베이스 시스템과 연결시켜서 데이터들이 보존하려고 합니다.

MySQL

1. MySQL 설치

Homebrew로 MySQL 데이터 베이스를 간단하게 설치할 수 있습니다.

brew install mysql

 

mysql_secure_installation 명령어를 실행해서 root 사용자의 비밀번호를 설정해줍니다.

mysql_secure_installation

 

brew를 통해 MySQL을 설치하면 아래와 같은 에러가 발생할 수 있습니다.

Error: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

 

이 경우 아래의 명령어로 재설치해줍니다.

# Homwbrew로 mysql을 설치한 경우 아래의 명령어로 해결 가능
brew services restart mysql

# 다시 비밀번호와 기본 옵션 설정
mysql_secure_installation

 

MySQL을 실행해줍니다.

mysql.server start

 

아래와 같은 메세지가 뜨면 성공한 것 입니다 !

"Starting MySQL SUCCESS!"

 

MySQL 데이터베이스의 현재 실행 여부 상태를 보고 싶으면 다음 명령어를 실행하면 됩니다.

mysql.server status

 

만약 MySQL 을 실행 정지하고 싶으면 다음 명령어를 실행해줍니다.

mysql.server stop

 

MySQL에 접속해봅시다.

  • -u: MySQL에 접속할 사용자의 아이디를 명시합니다. (root 사용자로 접속합니다.
  • -p: 비밀번호를 직접입력합니다.
mysql -u root -p

 

데이터 베이스를 생성합니다. test라는 이름의 데이터 베이스를 만들어보겠습니다.

CREATE DATABASE FLASK_BASIC;

 

데이터 베이스가 잘 생성되었는지 데이터 베이스 목록을 조회해봅시다.

SHOW DATABASES;

 

데이터베이스를 생성했으면 해당 데이터베이스를 사용한다는 것을 명시해줘야 합니다. use 명령어를 통해서 MySQL 데이터베이스 시스템에 알려줄 수 있습니다.

USE FLASK_BASIC;

 

이번에는 데이터 베이스를 생성하고 사용을 명시줬으니, 이번에는 테이블을 만들어봅시다. 회원가입과 관련된 정보를 저장할 테이블이기 때문에 아래와 같은 형태로 테이블 스키마를 설정해줍니다.

CREATE TABLE users(
    id INT NOT NULL AUTO_INCREMENT, # AUTO_INCREMENT: 해당 칼럼의 값이 자동으로 1씩 증가된다.
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    profile VARCHAR(1000) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id), # 고유키로 설정할 컬럼
    UNIQUE KEY email (email) # 해당 컬럼의 값이 중복되는 값이 존재하면 안됨
);

 

테이블이 잘 만들어졌는지 확인해봅시다. 아마 users 테이블이 만들어진 것을 확인할 수 있습니다.

SHOW TABLES;
+----------------+
| Tables_in_test |
+----------------+
| users          |
+----------------+

 

이번에는 users 테이블을 명시해서 확인해봅시다.

explain users;

 

위에서 정한 스카마데로 테이블이 만들어진 것을 확인할 수 있습니다.

+------------+--------------+------+-----+-------------------+-------------------+
| Field      | Type         | Null | Key | Default           | Extra             |
+------------+--------------+------+-----+-------------------+-------------------+
| id         | int          | NO   | PRI | NULL              | auto_increment    |
| name       | varchar(255) | NO   |     | NULL              |                   |
| email      | varchar(255) | NO   |     | NULL              |                   |
| created_at | timestamp    | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+------------+--------------+------+-----+-------------------+-------------------+

 

만약 테이블을 삭제하고 싶으면 아래의 명령어를 실행하면 됩니다.

drop table users;

 

2. MySQL을 Flask와 연동하기

데이터 베이스와 테이블을 성공적으로 만들었으니 이제는 Flask와 연동해봅시다. API에 MySQL을 연동하려면 SQLAlchemy라는 라이브러리를 설치해야 합니다. 이 라이브러리는 파이썬 코드로 데이터 베이스에 연결할 수 있도록 돕는 라이브러리 입니다.

pip install sqlalchemy

 

SQLAlchemy 에서 MySQL을 사용하기 위해서는 MySQL용 DBAPI 또한 설치해야합니다. DBAPI는 이름 그대로 DB를 사용하기 위한 API인데요. MySQL의 공식 파이썬 DBAPI인 MySQL -Connector를 사용해보겠습니다.

pip install mysql-connector-python

 

다음으로는 데이터베이스 연결 정보를 만들어봅시다. config.py 라는 이름으로 새로운 파일을 만들어줍니다. 

db = {
    # 데이터베이스에 접속할 사용자 아이디
    'user': 'root',
    # 사용자 비밀번호
    'password': 'test1234',
    # 접속할 데이터베이스의 주소 (같은 컴퓨터에 있는 데이터베이스에 접속하기 때문에 localhost)
    'host': 'localhost',
    # 관계형 데이터베이스는 주로 3306 포트를 통해 연결됨
    'port': 3306,
    # 실제 사용할 데이터베이스 이름
    'database': 'test'
}

DB_URL = f"mysql+mysqlconnector://{db['user']}:{db['password']}@{db['host']}:{db['port']}/{db['database']}?charset=utf8"

 

이제 데이터 베이스 연결 정보도 만들어줬으니 HTTP 요청을 통해 전달받은 회원의 정보를 데이터 베이스에 저장하는 코드를 작성해봅시다. 편의를 위해 sign-up.py 라는 새로운 파일을 만들고 아래의 코드를 작성해줍니다.

from flask      import Flask, request, jsonify, current_app
from flask.json import JSONEncoder
from sqlalchemy import create_engine, text

def get_user(user_id):
    user = current_app.database.execute(text("""
        SELECT 
            id,
            name,
            email,
            profile
        FROM users
        WHERE id = :user_id
    """), {
        'user_id' : user_id
    }).fetchone()

    return {
        'id'      : user['id'],
        'name'    : user['name'],
        'email'   : user['email'],
        'profile' : user['profile']
    } if user else None

# HTTP 요청을 통해 전달받은 회원가입 정보를 데이터 베이스에 저장함
def insert_user(user):
    return current_app.database.execute(text("""
        INSERT INTO users (
            name,
            email,
            profile,
            hashed_password
        ) VALUES (
            :name,
            :email,
            :profile,
            :password
        )
    """), user).lastrowid # 새로 사용자가 생성되면 새로 생성된 사용자의 아이디를 읽어들인다.

def create_app(test_config = None):
    app = Flask(__name__)
	
    # unit-test를 실행할 때 테스트 데이터 베이스에 대한 정보를 넣어준다.
    if test_config is None:
        app.config.from_pyfile("config.py")
    else:
        app.config.update(test_config)
	
    # 데이터 베이스와 연동해준다.
    database = create_engine(app.config['DB_URL'], encoding = 'utf-8', max_overflow = 0)
    app.database = database

    @app.route("/sign-up", methods=['POST'])
    def sign_up():
        new_user = request.json
        new_user_id = insert_user(new_user)
        new_user = get_user(new_user_id)

        return jsonify(new_user)

    return app

 

이제 서버를 다시 띄워봅시다. 

FLASK_APP=sign_up.py FLASK_DEBUG=1 flask run

 

이제 서버에 요청을 보내봅시다.

http -v POST http://127.0.0.1:5000/sign-up name=크리스토프 email=rhswl2135@gmail.com password=tada1234 profile="타다 데이터팀의 크리스토프 입니다. 반갑습니다."

 

다음과 같은 결과를 확인할 수 있습니다.

POST /sign-up HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 239
Content-Type: application/json
Host: 127.0.0.1:5000
User-Agent: HTTPie/2.4.0

{
    "email": "rhswl2135@gmail.com",
    "name": "크리스토프",
    "password": "tada1234",
    "profile": "타다 데이터팀의 크리스토프 입니다. 반갑습니다."
}


HTTP/1.0 200 OK
Content-Length: 238
Content-Type: application/json
Date: Wed, 05 May 2021 08:32:07 GMT
Server: Werkzeug/1.0.1 Python/3.7.10

{
    "email": "rhswl2135@gmail.com",
    "id": 1,
    "name": "크리스토프",
    "profile": "타다 데이터팀의 크리스토프 입니다. 반갑습니다."
}

 

이제 데이터가 잘 적재되었는지 확인해봅시다. mysql에 접속한 후 아래의 명령어로 테이블을 확인해봅시다.

SELECT * FROM users;

 

아래와 같은 결과를 확인할 수 있고, 데이터가 잘 적재된 것을 확인할 수 있습니다. 이제 서버를 종료하더라도 데이터 유실 없이 과거 데이터를 조회할 수 있습니다.

+----+-----------------+---------------------+----------+--------------------------------------------------------------------+---------------------+
| id | name            | email               | password | profile                                                            | created_at          |
+----+-----------------+---------------------+----------+--------------------------------------------------------------------+---------------------+
|  1 | 크리스토프      | rhswl2135@gmail.com | tada1234 | 타다 데이터팀의 크리스토프 입니다. 반갑습니다.                     | 2021-05-05 17:32:07 |
+----+-----------------+---------------------+----------+-----------------------------