< 메모장 앱의 API 서버 개발 >
※ 지금 까지 작성한 모든 개념을 적용해서 API 개발 프로젝트 진행
1) 화면 기획
2) MySQL Workbench를 실행시켜서 데이터에 맞게 DB와 Table 생성 및 전용 DB 커넥터 생성
3) Github에 레파지토리를 만들고, Window CMD에서 serverless로 API 폴더를 생성해서 Git 연동
- Git 연동할때 .gitignore 에 node_modules/ 넣어주어야함
- 왠만하면 이전에 잘실행된 파일꺼를 복사해서 사용하는게 좋음
4) Postman을 실행시켜서 API 기획 및 리퀘스트 생성
5) 기획한 API대로 Visual Studio Code에서 코드 작성
- app.py 파일과 API 경로에 맞게 오고가며 코드 작성 작업 진행
1. app.py 파일
from flask import Flask
from flask_jwt_extended import JWTManager
from flask_restful import Api
from config import Config
from resources.memo import MemoListResource, MemoResource
from resources.user import UserLoginResource, UserLogoutResource, UserRegisterResource
from resources.user import jwt_blacklist
app = Flask(__name__)
# 환경변수 셋팅
app.config.from_object(Config)
# JWT 매니저 초기화
jwt = JWTManager(app)
# 로그아웃된 토큰으로 요청하는 경우, 처리하는 함수 작성
@jwt.token_in_blocklist_loader
def check_if_token_is_revoked(jwt_header, jwt_payload) :
jti = jwt_payload['jti']
return jti in jwt_blacklist
api = Api(app)
# 경로(path)와 리소스(API 코드)를 연결한다.
# <int> flask 문법임 외워야됨
api.add_resource( UserRegisterResource , '/user/register')
api.add_resource( UserLoginResource , '/user/login')
api.add_resource( UserLogoutResource , '/user/logout')
api.add_resource( MemoListResource, '/memo')
api.add_resource( MemoResource, '/memo/<int:memo_id>')
if __name__ == '__main__' :
app.run()
2. config.py 파일
- 비번은 작성하면서 임의로 수정함
class Config :
# 대문자로 적는 이유는 바뀌지 않는 상수를 뜻하기 위해
# 앞으로는 접속 ID / PW 는 config로 관리 이 파일은 GIT hub에 올리면 안됨
HOST = 'yh-db.cp47575sk4u1po.ap-northeast-2.rds.amazonaws.com'
DATABASE = 'memo_db'
DB_USER = 'memo_user'
DB_PASSWORD = '2457'
# 실무에서 이 키값은 절대 노출되면 안됨
SALT = 'sad;kl7575sdlkf12@dkfj'
# JWT 관련 변수 셋팅
# 실무에서 이 키값은 절대 노출되면 안됨
JWT_SECRET_KEY = 'yhschool,2445522'
# False로 설정하면 유효기간이 없고, True로 설정하면 유효기간이 생긴다.
JWT_ACCESS_TOKEN_EXPIRES = False
PROPAGATE_EXCEPTIONS = True
3. mysql_connection.py 파일
from config import Config
import mysql.connector
# mysql db 에 접속하는 함수
def get_connection() :
connection = mysql.connector.connect(
host = Config.HOST ,
database = Config.DATABASE,
user = Config.DB_USER,
password = Config.DB_PASSWORD
)
return connection
4. API 개발은 resources 폴더를 생성하여 그안에 memo.py / user.py 파일을 생성하여 작성함
4-1. memo.py 파일
from flask import request
from flask_jwt_extended import get_jwt_identity, jwt_required
from flask_restful import Resource
from mysql_connection import get_connection
from mysql.connector import Error
class MemoListResource(Resource) :
# 메모 생성 API
@jwt_required()
def post(self) :
# 1. 클라이언트로부터 데이터를 받는다.
# body 데이터만 받는게 아니라 헤더 데이터도 받아야한다.
data = request.get_json()
user_id = get_jwt_identity()
# 2. 필수인 데이터가 없으면, 응답해준다.
# 3. DB에 저장한다.
try :
connection = get_connection()
query = '''insert into memo
(userId, title, date, content)
values
(%s, %s, %s, %s);'''
record = (user_id, data['title'], data['date'], data['content'])
cursor = connection.cursor()
cursor.execute(query, record)
connection.commit()
cursor.close()
connection.close()
except Error as e:
if cursor is not None :
cursor.close()
if connection is not None :
connection.close()
return {'result' : 'fail' , 'error' : str(e)}, 500
# 4. 클라이언트에게 응답
return {'result' : 'success'}, 200
# 내 메모 리스트를 가져오는 API
@jwt_required()
def get(self) :
# 1. 클라이언트로부터 데이터를 받는다.
user_id = get_jwt_identity()
# 2. db 쿼리한다.
try :
connection = get_connection()
query = '''select *
from memo
where userId = %s;'''
record = (user_id, )
cursor = connection.cursor(dictionary=True)
cursor.execute(query, record)
result_list = cursor.fetchall()
cursor.close()
connection.close()
except Error as e:
if cursor is not None:
cursor.close()
if connection is not None:
connection.close()
return {'result' : 'fail',
'error' : str(e)}, 500
# 3. 결과를 json 으로 응답한다.
i = 0
for row in result_list :
result_list[i]['date'] = row['date'].isoformat()
result_list[i]['createdAt'] = row['createdAt'].isoformat()
result_list[i]['updatedAt'] = row['updatedAt'].isoformat()
i = i + 1
if len(result_list) == 1 :
if result_list[0]['userId'] == user_id :
return {"item" : result_list[0],
"result" : "success"}
else :
return {"result" : "fail"}, 401
else :
return {"result": "fail",
"error" : "해당 아이디는 존재하지 않습니다."}, 400
class MemoResource(Resource) :
# 메모 수정하는 API
@jwt_required()
def put(self, memo_id) :
data = request.get_json()
user_id = get_jwt_identity()
try :
connection = get_connection()
query = '''update memo
set title = %s, date = %s, content = %s
where id = %s and userId = %s;'''
record = (data['title'],
data['date'],
data['content'],
memo_id,
user_id)
cursor = connection.cursor()
cursor.execute(query, record)
connection.commit()
cursor.close()
connection.close()
except Error as e:
if cursor is not None:
cursor.close()
if connection is not None:
connection.close()
return {'result' : 'fail',
'error' : str(e)}, 500
return {'result' : 'success'}
# 메모 삭제하는 API
@jwt_required()
def delete(self, memo_id) :
user_id = get_jwt_identity()
try :
connection = get_connection()
query = '''delete from memo
where id = %s and userId = %s;'''
record = (memo_id, user_id)
cursor = connection.cursor()
cursor.execute(query, record)
connection.commit()
cursor.close()
connection.close()
except Error as e:
if cursor is not None:
cursor.close()
if connection is not None:
connection.close()
return {'result' : 'fail',
'error' : str(e)}, 500
return {'result' : 'success'}
4-2. user.py 파일
from email_validator import EmailNotValidError, validate_email
from flask_jwt_extended import create_access_token, get_jwt, jwt_required
from flask_restful import Resource
from flask import request
from mysql_connection import get_connection
from mysql.connector import Error
from utils import check_password, hash_password
#회원가입 API
class UserRegisterResource(Resource) :
def post(self) :
# 1. 클라이언트(유저) 로부터 데이터를 받는다.
data = request.get_json()
print(data)
# 2. 이메일, 비번, 닉네임 모두 있는지 확인한다.
if 'email' not in data or 'password' not in <span
6) 개발된 코드를 로컬에서 테스트 진행
- flask run 실행 후 Postman 에서 테스트
7) 테스트에 문제가 없었다면 이제 서버에 배포 준비!
- serverless.yml과 requirements.txt 수정!
- serverless.yml 파일
# "service" is the name of this project. This will also be added to your AWS resource names.
service: aws-memo-server
frameworkVersion: '3'
custom:
wsgi:
app: app.app
provider:
name: aws
runtime: python3.10
region : ap-northeast-2
functions:
api:
handler: wsgi_handler.handler
events:
- http:
path: /
method: ANY
- http:
path: /{proxy+}
method: ANY
plugins:
- serverless-wsgi
- serverless-python-requirements
- requirements.txt
Flask==1.1.4
Werkzeug==1.0.1
markupsafe==2.0.1
flask-restful
mysql-connector-python
psycopg-binary
passlib
flask-jwt-extended
email-validator
# 저장후에 cmd창 실행시켜서 sls deploy 서버 배포 확인!
다음 게시글로 계속~!