From eb252307e82e2647098b2088a86ccbb216db428e Mon Sep 17 00:00:00 2001 From: jaehwang Date: Fri, 7 Nov 2025 13:50:56 +0900 Subject: [PATCH] =?UTF-8?q?blog=20CRUD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + api-server/app/main.py | 35 ++++--- api-server/app/module/mysql_utils.py | 113 +++++++++++++++++++++++ api-server/app/module/pydantic_models.py | 10 +- 4 files changed, 141 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 9377a7e..9868f9b 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,17 @@ Docker, Docker-compose ### Percona 설치 ./percona-server + .env.original 파일 보고 변수 원하는대로 바꿔 .env로 저장 + ``` docker compose -f docker-compose.percona.yml up -d ``` ### API Server 켜기 ./api-server + 해당 폴더에도 따로 .env.original이 있으니 percona와 동일하게 변경하고 .env로 저장 + Percona 서버를 사용하지 않을 시 해당하는 서버에 맞게 저장 ``` diff --git a/api-server/app/main.py b/api-server/app/main.py index 1448799..105dcfa 100644 --- a/api-server/app/main.py +++ b/api-server/app/main.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI, status +from fastapi import FastAPI, status, Depends from fastapi.responses import JSONResponse from module.pydantic_models import * import module.mysql_utils as sql @@ -8,32 +8,39 @@ app = FastAPI() @app.post("/user/create", status_code=status.HTTP_201_CREATED) async def create_user(params: UserCreateForm): user_id = await sql.create_user(params.user_name, params.phone_number) - return JSONResponse(content={'user_id' : user_id}) + return JSONResponse(content={'user_id' : user_id}, status_code=status.HTTP_201_CREATED) @app.post("/user/read", status_code=status.HTTP_200_OK) async def read_user(params: UserReadFromIdForm): user_info = await sql.get_user_info_from_id(params.user_id) return JSONResponse(content=user_info) -@app.post("/user/update", status_code=status.HTTP_200_OK) +@app.patch("/user/update", status_code=status.HTTP_200_OK) async def update_user(params: UserUpdatePhoneNumberFromIdForm): updated_data = await sql.update_user_phone_from_id(params.user_id, params.phone_number) return updated_data -@app.post("/user/delete", status_code=status.HTTP_204_NO_CONTENT) +@app.delete("/user/delete", status_code=status.HTTP_204_NO_CONTENT) async def delete_user(params: UserDeleteForm): await sql.delete_user_from_id(params.user_id) return -@app.post("/blog/create") +@app.post("/blog/create", status_code=status.HTTP_201_CREATED) async def create_blog(params: BlogCreateForm): - pass -@app.post("/blog/read") -async def read_blog(params: BlogReadForm): - pass -@app.post("/blog/update") -async def update_blog(params: BlogUpdateForm): - pass -@app.post("/blog/delete") + blog_id = await sql.create_blog(params.blog_owner, params.blog_title, params.blog_content) + return JSONResponse(content={'blog_id' : blog_id}, status_code=status.HTTP_201_CREATED) + +@app.post("/blog/read", status_code=status.HTTP_200_OK) +async def read_blog(params: BlogReadFromIdForm): + blog_info = await sql.get_blog_info_from_id(params.blog_id) + return JSONResponse(content=blog_info) + +@app.patch("/blog/update", status_code=status.HTTP_200_OK) +async def update_blog(params: BlogUpdateContentFromIdForm): + updated_data = await sql.update_blog_content_from_id(params.blog_id, params.blog_content) + return updated_data + +@app.delete("/blog/delete", status_code=status.HTTP_204_NO_CONTENT) async def delete_blog(params: BlogDeleteForm): - pass \ No newline at end of file + await sql.delete_blog_from_id(params.blog_id) + return \ No newline at end of file diff --git a/api-server/app/module/mysql_utils.py b/api-server/app/module/mysql_utils.py index e5d123b..95ae3c4 100644 --- a/api-server/app/module/mysql_utils.py +++ b/api-server/app/module/mysql_utils.py @@ -106,6 +106,17 @@ async def update_user_phone_from_id(user_id:int, phone_number:str=None): async def delete_user_from_id(user_id:int): async with await get_cnx() as cnx: async with await cnx.cursor() as cur: + count_query = ''' + SELECT count(*) + FROM user_table + WHERE user_id = %(user_id)s + ''' + await cur.execute(count_query, {'user_id' : user_id}) + found_rows = await cur.fetchone() + if found_rows[0] == 0: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + query = ''' DELETE FROM user_table @@ -122,5 +133,107 @@ async def delete_user_from_id(user_id:int): await cnx.commit() return +async def create_blog(blog_owner:int, blog_title:str, blog_content:str = None): + async with await get_cnx() as cnx: + async with await cnx.cursor() as cur: + query = ''' + INSERT INTO blog_table (blog_title, blog_content, blog_owner) + VALUES (%(blog_title)s, %(blog_content)s, %(blog_owner)s) + ''' + data = { + "blog_owner" : blog_owner, + "blog_title" : blog_title, + "blog_content" : blog_content + } + try: + await cur.execute(query, data) + except IntegrityError as e: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="blog already exist") + + blog_id = cur.lastrowid + print(blog_id) + await cnx.commit() + return blog_id + +async def get_blog_info_from_id(blog_id:int): + async with await get_cnx() as cnx: + async with await cnx.cursor() as cur: + query = ''' + SELECT blog_owner, blog_title, blog_content FROM blog_table + WHERE blog_id=%(blog_id)s + ''' + data = {"blog_id" : blog_id} + + await cur.execute(query, data) + user_info = await cur.fetchone() + await cnx.commit() + if not user_info: + raise HTTPException(status.HTTP_404_NOT_FOUND) + return user_info + +async def update_blog_content_from_id(blog_id:int, blog_content:str=None): + async with await get_cnx() as cnx: + async with await cnx.cursor() as cur: + count_query = ''' + SELECT count(*) + FROM blog_table + WHERE blog_id = %(blog_id)s + ''' + await cur.execute(count_query, {'blog_id' : blog_id}) + found_rows = await cur.fetchone() + if found_rows[0] == 0: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + query = ''' + UPDATE blog_table + SET blog_content = %(blog_content)s + WHERE blog_id = %(blog_id)s + ''' + data = { + "blog_id" : blog_id, + "blog_content" : blog_content + } + + await cur.execute(query, data) + + if cur.rowcount == 0: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_204_NO_CONTENT) + + await cnx.commit() + return data + + +async def delete_blog_from_id(blog_id:int): + async with await get_cnx() as cnx: + async with await cnx.cursor() as cur: + count_query = ''' + SELECT count(*) + FROM blog_table + WHERE blog_id = %(blog_id)s + ''' + await cur.execute(count_query, {'blog_id' : blog_id}) + found_rows = await cur.fetchone() + if found_rows[0] == 0: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + query = ''' + DELETE + FROM blog_table + WHERE blog_id = %(blog_id)s + ''' + data = { + "blog_id" : blog_id + } + try: + await cur.execute(query, data) + except IntegrityError as e: + await cnx.rollback() + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="already exist") + await cnx.commit() + return diff --git a/api-server/app/module/pydantic_models.py b/api-server/app/module/pydantic_models.py index 0cd443a..960ce55 100644 --- a/api-server/app/module/pydantic_models.py +++ b/api-server/app/module/pydantic_models.py @@ -16,20 +16,16 @@ class UserDeleteForm(BaseModel): class BlogCreateForm(BaseModel): - owner:int + blog_owner:int blog_title:str blog_content:str -class BlogReadForm(BaseModel): - owner:int +class BlogReadFromIdForm(BaseModel): blog_id:int -class BlogUpdateForm(BaseModel): - owner:int +class BlogUpdateContentFromIdForm(BaseModel): blog_id:int - blog_title:str blog_content:str class BlogDeleteForm(BaseModel): - owner:int blog_id:int \ No newline at end of file