VSCode + .editorconfig 그리고 quote
토요일.
javaScript로 개발을 한다는 것이 (아마도) 엄청난 성장기라 그런지 개발환경에 대한 설정과 설정 그리고 설정을 하면서 배우고 또 배우는 상황인듯 하다.
기존에 만들고 있던 Toy Project에 eslint와 prettier를 적용하면서 잘될거라는 기대도 없었지만 역시나 역시나 멀쩡히 잘 되던 부분이 안되는 현상이 있어 몇 시간 삽질을 하다가 Pure한 Template을 다시 구해서 해보고 결국 설정이라는 생각을 하고 있다.
Vite + Vu3 + eslint + prettier + VSCode 설정의 대환장파티를 히루 종일 해 보고 남은 건.
Toy Projet를 만들면서 발생하는 일들을 기록 해 본다.
목요일.
Toy Projet를 만들면서 발생하는 일들을 기록 해 본다.
- 2022-01-24
Toy Project를 하나 만들기로 하고Front Template을 하나 정해서 GitHub에 커밋을 한다. 이것을 만들게 된 계기를 적어보면, 오라클 무료 인스턴스에 개인적으로 사용할 페이지를 올려 사용할 요량이었는데, 아무래도 인증이 필요해서 이것저것 Template을 찾아보는데, 영 마음에 드는것이 없다.
거기다 그 즈음 보기시작한 Facebook의 개발자 커뮤니티에 올라오는 질문글들을 보면서, 내가 경험한 것들을 조금은 가다듬어 세상에 넘겨줘야 겠다는 생각을 하게 된다. 누군가에게는 도움이 되기를 바라면서 말이다.
- 2022-02-01
구글에서 도메인을 하나 구입했다. 목적은 https를 적용하려면 도메인이 필요했기 때문이기는 한데.
도메인을 구입하고, 오라클 무료 인스턴스를 2개로 늘려서 작업 구성을 하면서 즐거워 하는 나를 발견한다. - halfenif.github.io: GitHub Page를 블로그로 사용하는건 계속 될 것이다. - filemover.enif.page: 주력으로 사용 할 개인적인 것들을 모아두는 인스턴스이다. - livedemo.enif.page: 인터넷상에 공개 할 목적으로 만든 데모 사이트이다. - demo.vvtui5.enif.page : Vite + Vue3 + Tailwind + SAP UI5로 만들어진 Demo 사이트이다.
- 2022-02-03 10:03:45
어제 밤까지 작업은 내용을 클라우드에 올리고 확인을 해보는데.. 뭔가 FastAPI 호출형식이 맞지 않는 오류가 발생한다. 뭐 그러려니 하는데.. 로그 보는 것이 영 불편하다. FastAPI 로그는 아니 정확하게는 Uviconr에서 로그를 생성하는 부분을 살펴보는데, 로깅에 대한dict항목만 찾아지는 것이 이게 뭔가 싶다. Stack Overflow에서 config file(아니 dict) sample을 구해서 넣어보니 동작은 하는데, 에러는 출력되지 않는다. log level이 debug가 아니고 trace로 바꾸자 좀 더 나오는데.. 뭔가 마음에 들지는 않는다. FaceBook Python 사용자 그룹에도움을 요청 해 보고 딴 짓을 한 참 하다가 다시 보는데. 내가 수정한 Header 값으로 요청을 하고 있지 않다. Vite에서 Build오류가 발생하고있어서, dist의 내용물들이 갱신이 안되고 있는 현상이 있다. IMG 항목중 URL이 Local인데 실제 파일이 없는 경우… 뭐 그럴수있지.
- 2022-02-03 23:04:26
로그를 보다가 보다가.. 결국 Nginx Log를 포맷을 수정했고, FileBeat로 Nginx Log를 긁어다가 MySQL로 넣기 위해 JOSN형태의 File로 떨어뜨렸었다가.. 아닌거 같아 Redis에 넣는 것 까지는 되었는데.
이 녀석을 다시 MySql로 넣기 위해서 Python AppScheduler를 보기 시작했고.
개발을 위해 WSL에 Redis를 설치하고 한참을 해 보는데.. 단순하게 생각해서 서버에서 긁어온(=화면에 출력된) 문자열을 WSL에 설치된 레디스에 넣었더니 Type Error가 나온다.
WSL에 Filebeat를 설치해서 Redis에 데이터를 생성하고 테스트해야 정확하다고 본다.
- 2022-02-09

DemoSite의 Logo를 변경했다.
뭔가를 만들려면 상하좌우 모두 두루 살펴서 받아들이는 사람이 이질감 없이 수용 할 수 있도록 준비 해 주는 것이 좋다는 생각이다.
로고는favicon.io라는 곳을 이용했다.
- 2022-02-11 13:46:53
그 사이 많은 일들이 있었다.
우선 ESLint를 적용하는 과정에서 처음 사용했던Template을 버리고, ESLint를 적용한Template로 갈아탔다. 이것은 시간이 매우 많이 소요되는 작업이었지만, 어설프게 웹 개발을 경험하는 것에서 이제 좀 본격적으로 개발 해 본다는 느낌을 가지게 해 주었다.
ESLint를 적용하는 과정에서 이것 저것 프로젝트를 만들다보니 GitHub의 레파지토리가 너무 중구난방이라는 생각이 들어서 전체에 대한 명명규칙을 만들고, 사용하지 않는것들은 삭제했다 - dev** : 개발중인 레파지토리이다. 나중에 demo*_로 Branch될 후보군이다. - demo__ : 인터넷상에 공개한 레파지토리이다. - test** : 테스트를 위해서 만들어본 레파지토리들이다. - toy** : 취미로 만들어보는 것들을 모아두었다.
- 2022-02-11 14:26:04
Vue에서 SVG를 설정하는 것에 대해 알게되었다.
이것의 시작은 ESLint 문법오류를 전부 잡고 Build를 시도하는 작업이었는데, 얼마전에 집어넣은 log.svg에 대한 경로를 찾지 못하는 오류가 나오면서 시작되었다.
어떤 문제를 직면했을 때 인간은 본능적으로 자신이 경험해 온 것을 기반으로 추론하고 행동하게 되었다.(당연한거다.)
이번에는 운이좋았던 것인지, 2시간만에 vite.config.js에서 svgLoader라는 단어를 발견하고, 오류가 나던 logo.svg대신 logo.png를 적용해 봄으로써 그 전까지 세웠던 가설과 추론이 모두 헛된것이었음을 증명하고 문제를 종료시킨다. 참.. 배울게 많다.
- 2022-02-12 14:48:44
Vue를 계속 적용 해 보면서 느끼는 생각은. Vue라는 것이 마치 거대한 무더기인데 거의 정리가 안 된 카오스같은. 그러다 보니 뭔가를 하나 하려면, 이것이 올바른 방법인지 아닌지 검토하고 판단하기 위해 오피셜 레퍼런스를 보지만, (사실 거기에 기술된 것이 정답이겠지만) 조금만 옆으로 응용하거나 더 나가려고 하면 걸리는 것들이 있다. 오늘은 이제까지 계속 생각하고 있던 main.js가 아닌 다른 곳에서 app instance에 접근하는 방법에 대해 검토를 해보니. appContext라는 단어를 찾기까지 시간이 그래도 많이 소요되었다. 이것은 결국 아직 (내가) JavaScript라는 것과 Vue가 프레임워크로서의 구성을 어떻게 해 놨는지에 대한 이해가 부족하다는 것을 반증한다는 생각이다. 한 2시간을 들여서 검토해보고 해결은 했다.
- 2022-02-15 09:21:29
CSS File을 삭제했다. 정확하게는 CSS가 필요한 부분의 Scope를 정하고, 해당 파일 내부의 Style로 설정하는 것으로 변경한 것이다.
이 Toy Project가 지향하는 바가 디지이너 없이 웹 개발경험이 없는 개발자가 간단한 사이트를 만드는 것인것 만큼, 디자인에 들어갈 Effort를 배제하라는 의미이기도 하다.
- 2022-02-15 23:12:58
Facebook 인증을 개발환경에서 만든 것을 운영으로 올리려다 보니,개인정보 처리방안과서비스 약관이 마음에 걸려.
인터넷을 찾아봤으나 마음에 드는 것이 없어 직접 작성했다.
Jekyll minima에 Counter 구성하기
화요일.
Jekyll minima thema에는 (당연히) 기본으로 제공하는 카운터가 없어서 하나 만들어 보기로 한다.
카운터의 원리를 여러가지 생각 해 볼 수 있겠으나, 특정 URL로 요청을 하면 카운터 이미지를 되돌로주는 방식이다.
카운팅을 하기 위해서는 카운텅 숫자를 보관 할 필요가 있기에.. 그건 DB를 사용하기로 하고, 남은건 어떻게 이미지를 만들것인가? 인데.
요즘은 SVG라는 걸출한 포맷이 보편화되었기에 이미지가 아니라 String을 반환하면 되기는 한다.
알아야 하는 사항
- Python에는 SVG용 라이브러리가 아주 많은거 같은데, svgwriter가 많이 사용되는 것 같다.
- Counter를 다른 사용자 혹은 다른 곳에서 사용되면 곤란하기 때문에, 요청 ORGIN을 반드시 체크해야한다.
from os.path import join
import svgwrite
def get_counter_by_uuid(uuid: str):
# DB에서 uuid로 기 등록된 카운터를 받아오거나 없으면 신규로 Insert한다.
row = sql_get_count_by_uuid(uuid)
if row:
countNumber = row['READ_COUNT']
countStr = f'Read Count : [{countNumber}]'
else:
countStr = 'Read Count Fail!'
# 카운터 파일 저장 할 폴더를 하나 만들어 두고
filename = join(COUNTER_DATA_FOLDER, f'{uuid}.svg')
# 드로잉을 하나 만들면서 크기를 넣어주고
dwg = svgwrite.Drawing(filename, (200,16))
# 문자열을 집어 넣는다
dwg.add(dwg.text(countStr, insert=(0, 13), fill='black'))
# 파일로 저장한다
dwg.save()
# 파일명을 반환한다
return filename
자 이제 SVG파일을 만들었으면.. (이걸 열어보면 HTML Element이다.) 반환을 해야 하는데, 사용하고 있는 FastAPI에는 FileResponse라는 아주 좋은 기능이 있다.
Server에 vite로 build한 것 배포하기
월요일.
만들고있는 Toy Project(빨리 이름을 지어줘야 겠다.)를 배포하려고 보니..
운영서버에 node가 설치될 이유가 있는가?
- 나는 정적인 웹서버로 Nginx를 사용 할 예정이니, Node가 필요한 상황은 아니다
# 그러니 NPM을 설치할 이유는 없어 보인다.
- 빌드결과물을 어떻게 Cloud에 올릴 것인가?
# 개발환경이나 혼자 막 쓰는 녀석이라면 Github을 통해서 간편하게 구성 할 수 있겠지만.
scp를 사용하기로 하고 설정을 한다.
# WSL에서
# Key는 미리 등록되어 있어야 한다. 사용자명은 ubuntu라고하면
# build된 결과물이 dist에 있고, cloud에서는 ~/temp/front에서 작업 할 것이다.
tar -cvzf dist.tar.gz dist/
scp -i ~/.ssh/키파일명 dist.tar.gz ubuntu@클라우드IP:temp/front/dist.tar.gz
# Cloud에서
# Nginx Root Folder에 대한 권한 작업은 되어 있어야 한다
# 다 지우고 넣는다. 잘 생각하자.
rm -rf dist
tar -xvf dist.tar.gz
rm -rf /var/www/html/*
cp -r ./dist/* /var/www/html
Key File을 매번 입력하기 싫으면, .ssh에 config File을 만들어두면 간편하게 사용 할 수 있기는 하다. (나는 그렇게 쓰고 있다.)
Oracle Cloud SSH Key & IP Table
월요일. 음력으로는 올해의 마지막 날.
무료로 제공해줘서 잘쓰고 있는 오라클 클라우드 인스턴스에 지금 만들고 있는 Toy Project를 올리려고 작업을 한다.
- 인스턴스를 만들 때 Private Key File을 받아놓자.
Public Key를 받아놓을 필요가 있을까?
아직까지는 그런 경우를 알지 못한다.
- Windows는 좀 그러니 WSL ssh folder에 밀어넣고 600으로 퍼미션을 변경 해 둔다. 안그러면 퍼미션관련 오류메시지를 볼 것이다.
//WSL에서
chmod 600 파일명
- default user는 Ubuntu의 경우 ubuntu이다. 자기 id 넣고, 순간 당황하지 말자.
이게 습관이라는 것이 참 무서운것이다.
뭐가 문제인지 인식하는데 시간이 좀 걸렸다.
- 방화벽 정책을 등록하고. (이미 다른 인스턴스가 있으면 함께 적용가능 하다.)
//Web Instance 관리화면에서
Networking >> Virtual Cloud Networks >> 해당VNC >> Subnet Details
여기 Security Lists에 추가한다.
- IP Table을 열어준다
//Instance에서
sudo iptables -I INPUT 5 -i ens3 -p tcp --dport 포트번호 -m state --state NEW,ESTABLISHED -j ACCEPT
- 재부팅시에도 설정을 유지하도록 하고 재부팅해서 확인한다. (확인은 반드시 실행해서 확인해보는..좀 위험한 발상이기는 하다만.)
//Instance에서
sudo apt install iptables-persistent
sudo netfilter-persistent save
sudo reboot
Fast API JWT Example을 실행보면서 검토할 사항들
토요일.
운동을 가자고 하는 집사람의 요구를 쌩까면서 Java Spring으로 구현했던 JWT와 Python FastAPI에서 Example로 제공하는 JWT를 비교 해 보고 있다.
먼저 알아야 하는 사항
- OAuth2PasswordRequestForm
- OAuth2PasswordBearer
이 두 가지가 무엇인지 정확하게 식별해놓지 않은 상태에서 Example을 보고 따라하면 통상적으로 하려고 했던것에서 많이 어긋나는 상황이 발생하는듯하다.
OAuth2PasswordRequestForm
아래 이미지 두 개를 보자.

저 오른쪽 노란색 자물쇠가 있는 함수와 없는 함수의 차이를 생각하자.
@app.get("/items_fastapi_jwt/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
저 자물쇠가 나오는 조건은 OAuth2PasswordBearer유형의 Dependency Injection인 경우 출력되는 것으로 유추된다.
VSCode 단축키 설정
토요일.
VSCode를 주 개발도구로 바꾸고 나서, Python과 JavaScript를 동시에 사용하다가 보니, Python에서 Console.log()를 찍고 있고, JavaScript에서 print()를 찍고 있는게 당연한건 아니다.
귀찬으면 뭔가 개선을 해야 해서 좀 찾아보니 VSCode Snipet에 잘 정리가 되어 있다.
[
{
"key": "ctrl+shift+a",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "console.log(`${CLIPBOARD}:`,${CLIPBOARD});"
}
},
{
"key": "ctrl+shift+z",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "print(f'${CLIPBOARD}:', $CLIPBOARD)"
}
}
]
일단 내가 사용하는 스타일을 보니 변수명을 복사 한 다음 그 녀석을 찍어보겠다는 생각이니, 손가락이 가까운 a와 z를 하나씩 각인시켜본다.
VSCode + FastAPI 디버깅을 하려는데 No operations defined in spec!
금요일.
아주 예전에 FastAPI에서 JWT 구현했던 것을 끄집어 내서 Toy Project에 붙여넣으며 VSCode에서 디버깅을 하려는데 함수가 하나도 보이지 않는다.

No operations defined in spec!
이 말의 의미를 찬찬히 되새겨봤다면 금방 이해를 했을터인데, 다른 문제인가 싶어서 좀 해매기 시작한다.
# VSCOde Debug용 main은 아래쪽에 있어야 한다.
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
디버깅을 위해 만들어둔 ****name****을 소스정리하면서 위쪽으로 아무생각 없이 올려두었더니, 그 아래쪽으로는 인식을 못했나 보다.
결론
Stack Overflow에 뭔가를 찾으려 해도 키워드가 애매하면 엉뚱한 것만 나온다.
Python SQLAlchemy + MySQL 파라메터 형식에 대해서
목요일.
아주 예전에 Oracle로 구현해뒀던 JWT를 다시 꺼내서 MySql로 바꾸는 작업을 하고 있었다.
sql = """
SELECT USER_ID
,USER_NAME
,PASSWORD
FROM TB_USER_BAS
WHERE USER_ID = :USER_ID
"""
params = { "USER_ID": userid }
Argument 2 must be Tuple or List!
변경된 부분은 아마도 Python에서 MySql을 사용하기 위해 Mysql Connector를 다시 설정해야 하는 부분이 아니었을까 싶지만, 메시지는 매우 당혹스러운 느낌으로 다가온다.
sql = """
SELECT USER_ID
,USER_NAME
,PASSWORD
FROM TB_USER_BAS
WHERE USER_ID = %(USER_ID)s
"""
params = { "USER_ID": userid }
한참을 찾다가 MySql Connector Python Page에서 표현식이 다른 것을 보고 적용을 해 보니 된다.
Python base64 decode 에러나는 상황
월요일.
아주가끔은 아니고 한 10번에 한 번은 아래와 같은 오류가 발생했다.
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb1 in position 0: invalid start byte
이것에 대해서 찾아보면 utf-8이 3Byte라서.. 어쩌구 하는 게시물도 있기는 했지만 테스트 해보니 정답은 아닌거 같고.
def getDecode(msg):
msg_byte = base64.b64decode(msg)
# 원래코드
return msg_byte.decode('utf-8')
# 변경된 코드
return msg_byte.decode('utf-16-be')
결론(아직까지는 문제없음)
- utf-8을 utf-16-be로 바꾼다 (utf-16, utf-16-be, utf-16-le의 차이점도 알아두면 나쁘지 않다.)
- 이런저런 사정으로 utf-8에서 제외되는 문자가 있는 모양이다.
- utf-8 vs. utf-16의 문제가 아니었다.
python: Invalid base64-encoded string: number of data characters (37) cannot be 1 more than a multiple of 4
이번에는 이런 오류가 발생하고 있어 구글링을 해 보니 stack overflow에 바로 해당 내용이 나온다