MySQL과 Flask API를 연동하기

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 protected] 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": "[email protected]", "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": "[email protected]", "id": 1, "name": "크리스토프", "profile": "타다 데이터팀의 크리스토프 입니다. 반갑습니다." }

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

SELECT * FROM users;

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

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

from http://problem-solving.tistory.com/10 by ccl(A) rewrite - 2021-10-26 17:27:11