API 개발/API 개발 Project

API Project : 메모앱 API 서버 개발

신강희 2024. 5. 29. 15:27
728x90

< 메모장 앱의 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 서버 배포 확인!

 

다음 게시글로 계속~!

반응형