-
pymysql 사용하기
서론API를 만들면서 또 DB를 안쓸 수가 없다.연결하는 방법은 수 많이 있겠지만 필자가 편한 기준으로 설명을 해보려한다.SQL서버에 접속을 하려면 접속할 정보가 필요하다.이 정보가 유출되면 좋지 못한 결과를 맛볼지 모른다.이런 민감한 접속정보, key파일 등과 같은 정보들은 git 에도 올리지 않아야 한다.고로 config.json 이라는 파일을 하나 만들어 온라인상으로 업로드 하지 않고 내부적으로만 사용하길 바란다. 설치bash pip install pymysql먼저 pymysql를 선행적으로 설치를 함으로써 준비는 끝이 난다. 사용다음과 같이 connection.py 파일을 만들어보자.pythonimport pymysqlimport pymysql.cursorsimport jsonimport osimport tracebackclass Connectiondef initselfself.config self.readconfigself.conn Noneself.cur Noneself.connectdef readconfigselfwith openos.path.joinos.getcwd, config.json, r as fdata f.readdata json.loadsdataf.closereturn datadef connectselfself.conn pymysql.connecthostself.confighost,userself.configuser,passwordself.configpassword,dbself.configdb,charsetself.configcharset,cursorclasspymysql.cursors.DictCursor,autocommitFalseself.cur self.conn.cursorself.cur.executeset session autocommit0self.cur.executeset session transaction isolation level read committeddef executeself, sqltryself.cur.executesqlresult self.cur.fetchallself.conn.commitreturn resultexcept Exception as eself.conn.rollbacktraceback.printexcprintf execute error e finallyself.disconnectdef disconnectselftryself.cur.closeself.conn.closeexcept Exception as etraceback.printexcprintf disconnect error e 한번 함수를 읽어보자.1. def readconfig config.json 이라는 파일로부터 정보를 읽는다.2. def connect 읽은 파일을 기반으로 SQL 서버에 접속한다.3. def execute 접속된 SQL 서버에 SQL문을 보낸다.4. def disconnect 해당 세션의 접속을 종료한다.jsonhost 여기에 주소,port 포트 번호,user 사용자 명,password 이건 비밀번호,db 데이터베이스 이름,charset utf8mb4이번엔 위와 같이 config.json 파일도 함께 만들어 주자.이제 기본적인 코드는 완성이 되었다. 질문왜 fastAPI 메인에 해당 pymysql 객체를 한번만 만들어 재활용 하면 되지 않느냐 라고 생각 할 수 있다.최초에는 그렇게 설계를 했었는데 커낵션 실패 및 끊김, 성능 저하 등의 이슈가 발생했다.또한 모든 API 들이 DB를 사용하는 것은 아니다.고로 DB를 필요로 하는 API에서만 단발적으로 연결 후 바로 끊는 설계인 위 코드처럼 작성하였다.최소 선언 후 커넥션을 끊지않고 유지 했을 때 이슈를 GPT가 아래와 같이 요렇게 친절히 알려준다.연결 유실 Connection LossMySQL 서버 또는 네트워크에 일시적인 문제가 발생하면 기존 커넥션이 끊어질 수 있습니다. 이 경우 API 서버는 여전히 유효하지 않은 커넥션을 사용하려 할 것이며, 이는 쿼리 실패나 예외로 이어질 수 있습니다.커넥션 타임아웃 Connection TimeoutMySQL 서버는 일반적으로 오래된 유휴 커넥션을 자동으로 종료시키는 설정을 가지고 있습니다 waittimeout 및 interactivetimeout. 만약 API 서버가 일정 시간 동안 커넥션을 사용하지 않으면, 해당 커넥션이 타임아웃되어 끊어질 수 있습니다. 이후에 커넥션이 끊어진 상태에서 쿼리를 시도하면 오류가 발생합니다.커넥션 풀링 미사용 Lack of Connection Pooling하나의 커넥션만 재사용할 경우, 다수의 요청을 동시에 처리할 때 병목 현상이 발생할 수 있습니다. 이는 성능 저하로 이어지며, 특히 트래픽이 많은 서버에서는 문제가 될 수 있습니다. 커넥션 풀을 사용하면 여러 커넥션을 관리하고 필요에 따라 새로운 커넥션을 생성할 수 있어 병목을 줄일 수 있습니다.리소스 누수 Resource Leakage서버에서 커넥션이 제대로 해제되지 않거나 관리되지 않으면, 리소스가 누수되어 결국 서버가 다운될 수 있습니다. 예를 들어, 커넥션을 재사용하지 않거나 필요한 순간에 닫지 않으면 MySQL의 연결 수 제한을 초과할 수 있습니다.변경된 DB 상태 반영 실패DB 서버에서 설정 변경예 인증 메커니즘 변경, 커넥션 설정 변경 등이 발생했을 때, 기존 커넥션으로는 새로운 설정이 적용되지 않을 수 있습니다. 이로 인해 예상치 못한 오류나 접근 문제 등이 발생할 수 있습니다. 예시DB 에 과일의 판매 정보가 있다고 가정해보자 그리고 테이블 정보는 다음과 같다고 해보자.sqlcreate table fruitseq int autoincrement primary key comment 시퀀스 넘버,name varchar10 not null comment 과일 이름,price int not null comment 과일 가격그리고 데이터는 아래와 같이 있다고 가정해보자 seq name price1 사과 100 2 바나나 200 3 한라봉 300 가장 비싼 과일의 이름 을 가져오는 API를 만들어 보자pythonimport jsonfrom fastapi import FastAPI, Depends, Response, status, HTTPExceptionfrom pydantic import BaseModelfrom typing import Optionalfrom connection import Connectionapp FastAPIdocsurlv1docs, redocurlv1redoc ... 생략app.postgetexpensivefruit, statuscodestatus.HTTP200OKdef getexpensivefruitdbcon Connectionsql select namefrom fruitwhere price select maxprice from fruitresult dbcon.executesqlreturn Responsestatuscodestatus.HTTP200OK, contentjson.dumpsresult0해당 함수를 호출 하면 아래와 같은 결과를 받을 수 있다.jsonname 한라봉바로 여기는 샘플이 있는 깃허브httpsgithub.comnuienuieclassfastapi
2024-08-20 21:09:59
Public
-
응답코드 튜닝하기
서론api 를 사용하는데 응답코드가 뭘 하든 200 이 뜬다면 어처구니가 없을 테다.응답코드를 반환 하는 로직을 작성해보자. 로그인 로직응답코드를 만들기 전에 로그인 API 가 뭔가 기능을 하게 만들어 보자.pythonfrom fastapi import FastAPI, Dependsfrom pydantic import BaseModelfrom typing import Optionalapp FastAPIdocsurlv1docs, redocurlv1redocclass loginBaseModelid strpw strisguest Optionalbool Falseadmininfo id admin,pw 1234,app.postlogindef logindata logindata Depends 전역변수로 지정된 id 값과 일치하면 통과if data.id admininfoid 전역변수로 지정된 pw 값과 일치하면 통과if data.pw admininfopwreturn successelsereturn passworderrorelsereturn denied해당 로직은 id, pw 가 일치하는지만 검사한다.한번 틀리게 입력해보자.denied 값을 리턴 받았는데 응답코드는 200 이다.......아주 불편할 수가 없다.다음과 같이 수정해보자.pythonfrom fastapi import FastAPI, Depends, Response, statusfrom pydantic import BaseModelfrom typing import Optionalapp FastAPIdocsurlv1docs, redocurlv1redocclass logindataBaseModelid strpw strisguest Optionalbool Falseadmininfo id admin,pw 1234,app.postlogindef logindata logindata Depends 전역변수로 지정된 id 값과 일치하면 통과if data.id admininfoid 전역변수로 지정된 pw 값과 일치하면 통과if data.pw admininfopwreturn successelsereturn passworderrorelsereturn Responsestatuscodestatus.HTTP403FORBIDDEN, contentdenied요로코롬 상태 코드가 변경되었다.근데 공식문서에선 다음과 같이 하길 권장한다.다시 한번 변경 해보자.pythonfrom fastapi import FastAPI, Depends, Response, status, HTTPExceptionfrom pydantic import BaseModelfrom typing import Optionalapp FastAPIdocsurlv1docs, redocurlv1redocclass logindataBaseModelid strpw strisguest Optionalbool Falseadmininfo id admin,pw 1234,app.postlogindef logindata logindata Depends 전역변수로 지정된 id 값과 일치하면 통과if data.id admininfoid 전역변수로 지정된 pw 값과 일치하면 통과if data.pw admininfopwreturn successelsereturn passworderrorelseraise HTTPExceptionstatuscodestatus.HTTP403FORBIDDEN, detaildenied두 개의 docs 사진 상에서는 사실 응답코드도 정확하고 별반 차이가 없어 보인다.그래도 공식문서의 권장을 따라서 작성하도록 하자.이제 나머지도 리턴을 해보도록 하자pythonfrom fastapi import FastAPI, Depends, Response, status, HTTPExceptionfrom pydantic import BaseModelfrom typing import Optionalapp FastAPIdocsurlv1docs, redocurlv1redocclass logindataBaseModelid strpw strisguest Optionalbool Falseadmininfo id admin,pw 1234,app.postlogin, statuscodestatus.HTTP200OKdef logindata logindata Depends 전역변수로 지정된 id 값과 일치하면 통과if data.id admininfoid 전역변수로 지정된 pw 값과 일치하면 통과if data.pw admininfopwreturn Responsestatuscodestatus.HTTP200OKelseraise HTTPExceptionstatuscodestatus.HTTP401UNAUTHORIZED, detailpassworderrorelseraise HTTPExceptionstatuscodestatus.HTTP403FORBIDDEN, detaildeniedapi 작성은 완료 되었고 테스트를 한번에 하기 위해 다음과 같이 코드를 작성하였다.물론 docs 를 이용하여 3번에 걸쳐 해볼 수 있겠지만 이럴 때는 그냥 코드 짜는게 편하다.bash pip install requests아마 requests 가 없을 테니 먼저 설치하도록 하자.아래 test.py 를 하나 만들어 실행 해보자.pythonimport requestsdef logintestdata id test,pw 111response requests.posthttp127.0.0.18000login, paramsdataprintresponse 전부 틀리기 1 , response.statuscodedata id admin,pw 5678response requests.posthttp127.0.0.18000login, paramsdataprintresponse 비번 틀리게 2 , response.statuscodedata id admin,pw 1234response requests.posthttp127.0.0.18000login, paramsdataprintresponse 정확하게 3 , response.statuscode결과response 전부 틀리기 1 403response 비번 틀리게 2 401response 정확하게 3 200의도대로 너무나 잘 작동한다.
2024-08-16 19:23:53
Public
-
편하게 목록 보기
서론API 테스트 할려면 postman 이나 코드로 직접 짜서 매번 테스트 하기가 아주아주 번거로울 수가 없다.이럴 때를 위해 fastAPI는 친절하게 swagger 를 사용하는 docs 기능을 제공해준다.좀더 이쁜 redoc 이라는 기능도 있다. DOCS서버를 오픈한 후 맨뒤에 docs 만 추가해주면 아래와 같이 아주 멋진 테스트 화면을 볼 수 있다.redoc 은 좀더 이쁘게 보인다. 근데 redoc은 커스텀이 까다로워서 딱히 안쓴다.이제 백엔드 개발이나 개인적으로 볼 때나 위 docs 페이지를 활용하면 너무나 편하게 공유 및 테스트가 가능하다.docs 가 마음에 안들면 경로도 바꿀 수 있다.문론 redoc 도 변경 할 수 있다.pythonfrom fastapi import FastAPIapp FastAPIdocsurlv1docs, redocurlv1redocapp.getgettestdef testreturn Hello getapp.postposttestdef testreturn Hello post이제 v1docs 로 가야 볼 수 있게 되었다.또한 v1redoc 로 가야 볼 수 있다. 파라미터 받기이제 파라미터를 받아볼 터인데 심플하게 파라미터 검사 로직을 직접 만들어도 되지만, 기본 기능을 사용하면 좋다.예를 들어 id, pw를 전달 받는 로그인 api 를 만들어 본다 가정하자.여기httpsfastapi.tiangolo.comtutorialpathparams에 파라미터를 받는 방법들이 상세히 작성되어 있다.샘플로 아래와 같이 작성해보았다.pythonapp.getloginidpwdef loginid, pwdata id id,pw pwreturn data해당 api 를 스웨거에서 확인해보면이렇게 볼 수 있다.근데 누가 로그인을 get 으로 하는가 post로 바꿔보자.추가로 로그인 정보를 담고 있는 class로 파라미터를 관리해보자.pythonfrom fastapi import FastAPI, Dependsfrom pydantic import BaseModelapp FastAPIdocsurlv1docs, redocurlv1redocclass loginBaseModelid strpw strapp.postlogindef logindata login Dependsreturn data몇 가지 코드가 추가 되었다.이렇게 class 로 파라미터를 정리하면 나중에 유지 보수가 편하다.물론 아래와 같이 작성할 수도 있다.pythonapp.postlogindef logindata dict Dependsloginreturn data뭐 방법은 많은데 헤깔리테니 첫 번째로 고안한 방법만 활용 해보도록 한다.어차피 까먹으니까 옵셔널근데 하다보니 login api 에서 딱히 쓸일은 없겠지만 guest 라는 기능이 있다 치자.guest 은 기본값이 있고 값을 줘도 되고 안줘도 되는 파라미터라 치자.pythonfrom fastapi import FastAPI, Dependsfrom pydantic import BaseModelfrom typing import Optionalapp FastAPIdocsurlv1docs, redocurlv1redocclass loginBaseModelid strpw strisguest Optionalbool Falseapp.postlogindef logindata dict Dependsloginreturn data요로코롬 변경 하였다.자 한번 docs 로 봐보자.이야 이제 옵션값이 있는 파라미터도 만들어 볼줄 알게 되었다.이렇게 docs 를 활용하는 방법을 알아보았다.
2024-08-16 18:25:11
Public
-
fastAPI 시작하기
서론API 를 만드는 방법은 굉장히 많다.구글에 검색만 해봐도 다양한 방법이 나온다.그중에 킹갓 fastAPI를 사용해 볼 것이다.왜냐면 python 으로 아주아주 심플하게 또, 빠르게 만들 수 있기 때문이다.링크httpsfastapi.tiangolo.comko 에서 아주아주 친절한 설명을 볼수 있다.물론 공식 문서로부터 얻는 정보가 훨씬 유익하겠지만,어떤 특정한 기능은 설명이 없거나 부실하다.그러하여 fastAPI를 쓰면서 알아둔 팁들을 기록하는 형식으로 작성하겠다. 깃허브 주소아주 친절하게 노하우를 담은 공개 프로젝트도 하나 만들어 놓았다.샘플로 참고하면 좋을 듯 하다.바로 여기httpsgithub.comnuienuieclassfastapi 라이브러리bash pip install fastapi뭐 당연하겠지만 fastAPI를 쓸라면 fastAPI 라이브러리를 필요로 한다. 설치해준다.bash pip install uvicornstandard pip install gunicorn이제 테스트하거나, 운영할라믄 서버를 열어야하는데 테스트 단계에서는 미들웨어인 uvicorn를 쓸 것이고실제 운영의 경우 gunicorn 미들웨어를 사용할 것이다. 참고로 gunicorn은 윈도우 환경에서 실행을 못한다.이 둘의 차이는 구글 검색으로 쉽게 알아낼 수 있다. 기본 코드pythonfrom fastapi import FastAPIapp FastAPIapp.getgettestdef testreturn Hello getapp.postposttestdef testreturn Hello post기본 구조는 위와 같다.벌써 우리는 기능을 가진 api 두 개를 만들어 보았다. 실행bash uvicorn mainappINFO Started server process 25872INFO Waiting for application startup.INFO Application startup complete.INFO Uvicorn running on http127.0.0.18000 Press CTRLC to quit정말 단순 하게 uvicorn 을 입력하고 main 이라는 이름을 가진 .py 안에 있는 app 이라 명시된 FastAPI 객체를 호출하여 서버를 구동 시켰다.이제 get API 를 테스트하려 http127.0.0.18000gettest 으로 접속해보자.이렇게 우리는 단 몇 줄의 코드 만으로 기능을 하는 API를 만들었다. 팁실행을 했는데 코드 수정을 하게되면 서버를 껐다 켜야 수정된 코드가 반영이 된다.이 귀찮은 작업을 자동으로 해주는 옵션이 있는데 아래와 같이 하면 자동적으로 수정을 감지하여 재부팅한다.bash uvicorn mainapp reload또 따로 8000 포트로 다른 서비스를 열어뒀다면 당연하게도 포트 변경도 가능하다.bash uvicorn mainapp reload port 8282본 서비스를 정식 오픈 전에 내부망으로 다른 PC에서 테스트를 해보고 싶다.라고 한다면 아래 처럼 모든 접속을 허용해주어야 한다.로컬 IP port 로 조합하여 내부망에서 테스트 해볼 수 있다.이때 L3 장비공유기에서 설정이 필요할 수도 있다.bash uvicorn mainapp reload port 8282 host 0.0.0.0많은 커넥션을 테스트 해보기 위해 워커를 늘릴 수도 있다.노동자를 더 많이 할당 하여면 아래와 같이 한다. 근데 주의할 점은 reload를 사용한 상태면, workers 옵션이 씹힌다.bash uvicorn mainapp port 8282 host 0.0.0.0 workers 10
2024-08-16 17:26:25
Public