26 Jun 2022
API
Flask -> jinja2 사용하기
이전에는 html(클라이언트단)에서 ajax로 get타입을 받아와서
let word = '{{ word }}'
$.ajax({
type: "GET",
url: `apiUrl/${word}`,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Token [내토큰]");
},
data: {},
error: function (xhr, status, error) {
alert("에러 발생!");
},
success: function (response) {
console.log(response)
}
});
-> api 요청보내기
$("selector").text(response["변수"]);
javascript로 html에 출력했다면
flask에선
app.py(서버단)에서 requests로 get을 받아와서
r = requests.get("apiUrl/{keyword}", headers={"Authorization": "Token [내토큰]"})
result = r.json()
print(result)
-> flask에서 요청보내기(app.py)
<div>{{ result.변수 }}</div>
-> api에서 보내지는 변수(html)
html에 렌더링을 변수로 보내고 jinja2로 직접 html에 받아온 변수를 넣어 출력
return render_template("보낼html",html에서받는변수=보내는변수)
{% set 변수 = 받은변수[index].하위속성 %}
{% if 변수 > 값 %}
{% for 단일변수 in 복수변수 %}
{{ 단일변수.하위속성 }}
{% endfor %}
{% endif %}
파라미터 값 가져오기
hostname?param=value
@app.route('/페이지')
def 변수():
서버에서받은변수 = requsts.args.get("param")
return render_template("페이지", 보낼변수=서버에서받은변수)
or
@app.route('/페이지/<param>')
def 변수(param):
return render_template("페이지", 보낼변수=param)
회원가입 API
post타입으로 보내면 requests로 받아서 저장하는데 password의 경우 암호화를 위해 해시함수를 이용한다.
해시함수란?
알고리즘의 한 종류로서 임의의 데이터를 입력 받아 항상 고정된 길이의 임의의 값으로 변환해주는 함수
- 동일한 입력값은 항상 같은 결과값이 나옴
- 입력값이 조금이라도 달라지면 완전히 다른 값이 나옴
- 결과값을 통해 입력값을 알아내는 것이 불가능
-> 강의에서 사용해본 SHA256은 항상 256바이트의 결과값이 나온다.
pw_hash = hashlib.sha256((패스워드request변수).encode('utf-8')).hexdigest()
result = db.user.insert_one({...,'pw':pw_hash,...})
return jsonify({'result':'success'})//성공하면 success라는 문구가 result로 보내짐
로그인 때도 유저가 입력한 값을 hash함수를 이용해서 암호화하고 암호화된 패스워드로 find_one을 한다.
기본적으로 API는 open api를 제공하는 곳에 상세한 document들이 있어서 그걸 참고하면 좋다.
Api 참고링크 1
Api 참고링크 2
JWT
유저가 로그인을 하면 그 로그인상태를 유지시켜줘야 하는데 기본적으로 cookie, session 그리고 JWT 방식이 있다.
session 방식은 어설프게나마 해본 적이 있는데 JWT는 처음이었다.
로그인을 할 때 유저가 입력한 input값이 db와 일치하는지 체크하고
result = db.user.find_one({'id',id_receive, 'pw':pw_hash})
찾으면 JWT 토큰을 만들어 발급한다.
if result is not None:
//if(result != null)같은...
payload = {
'id': id_receive,
'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=5)//5초 뒤에 만료
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode('utf-8')
return jsonify({'result':'success','token':token})
else:
return jsonify({...실패처리...})
JWT 토큰에는 payload와 시크릿키가 필요하다.
시크릿키가 있어야 토큰을 디코딩해서 payload 값을 볼 수 있기 때문.
즉, JWT 토큰을 풀면 유저ID값을 알 수 있기 때문에 exp에 만료시간을 넣었다.
만료시간이 지나면 시크릿키로 토큰을 풀 때 만료되었다고 에러가 난다.
유저 정보를 찾을 때는(유저 id나 닉네임을 html에서 호출해야 할 필요가 있을 때)
token_receibe = request.cookies.get('mytoken')
유효한 토큰 확인하고(만료되지 않은) try except를 써서 로그인 할 때 encode를 하는 것과는 반대로 decode를 해서 payload를 출력하고 그 payload id로 db에서 유저 정보를 찾고 return json으로 보내주면 된다.
만약 토큰이 만료되었으면
except jwt.ExpiredSignatureError:
return jsonify({만료되었다는 메시지 호출});
db에 유저 정보가 없으면(디코딩 에러)
except jwt.exceptions.DecodeError:
return jsonify({정보가 없다는 메시지 호출})
JWT가 알고 있던 방식(클라이언트 헤더에 저장했다가 불러오는 방식)과 강의에서 본 방식(서버에서 바로 불러오는 방식)이 다른 이유
(이대호 기술매니저님의 답변)
알고 있던 방식은 서버와 클라이언트가 분리되어 작업하기 때문에 서버단에서 토큰을 바로 가져오기 어려워서 그 방식을 취했던 것.
하지만 flask에서 개발할 때는 서버와 클라이언트가 분리되어 있지 않아 바로 서버에서 불러와 쓸 수 있기 때문에 클라이언트단에 저장하지 않는다.
JWT 참고링크 3
23 Jun 2022
마지막 날
드디어(?) 웹개발 미니 프로젝트의 마지막 날.
이미 어제 다 마무리가 된 우리 팀은 제출하라는 양식으로 작업을 다 해서 보내기만 하면 됐다(ㅋㅋ).
그래서 제출 폼 링크를 받기 전까지 개인공부를 하다가 제출폼 링크가 슬랙에 뜨자마자 확인하고 폼을 작성했다.
근데 제출 폼에 JWT방식과 쿠키/세션방식의 차이라거나 서버사이드의 이점이라거나 고민해봐야할 문제가 있어서 팀원들과 이야기 나누고(사실 강의 듣는 느낌으로 끄덕끄덕만 함ㅋㅋ) 레퍼런스 사이트 링크 공유하면서 문서를 정리하고-도 이른 시간이어서(ㅋㅋ) 너무 일찍 보내면 싸가지 없어 보이지 않을까 하는(ㅋㅋㅋㅋ) 걱정 때문에 다른 조에서 먼저 보내길 기다렸다가 제출을 했다.
다음은
18시 프로젝트가 마감되고, 20시에 멘토님께 회고 멘토링을 받으면서 궁금했던 것을 질문하고, 사이트 문제를 어떻게 해결했는지 말씀드리고 항해에서의 첫번째 프로젝트가 끝이 났다.
물론 끝이 끝이 아니고 이제 시작이지만(ㅋㅋㅋ) 바로 내일부터는 주특기별로 조가 다시 편성되고, 각자 주특기(javascipt/java)를 활용한 알고리즘 문제 공부가 시작된다.
잘 따라갈 수 있을지 벌써부터 걱정이다ㅠㅠ
22 Jun 2022
코딩
2일차
나는 작업이 끝나기도 했고 마이페이지를 담당했던 팀원의 프로그램 문제로(말 그대로 알 수 없는 프로그램의 오류…) 마이페이지도 일부 맡았다(메인과 같은 포맷이었기 때문에).
그러나 또 생각보다 빨리 끝나버려서(사실 포맷은 index랑 같아서 복붙하면 되는 거고 db list에서는 어차피 gnb에 username을 호출하기 때문에 조건문으로 posting username과 로그인한 username이 일치하는 걸 뿌려주기만 하는 간단한 거였어서) 원래대로라면 썸네일을 클릭했을 때 유튜브로 링크를 열게 하는 게 계획이었지만 시간이 남는김에(ㅋㅋ) video 페이지도 코딩을 해서 사이트에서 유튜브 쇼츠도 감상할 수 있게 했다.
근데도 시간이 남아서(사실 원래 했던 작업과 크게 다르지 않았다. 작업 환경이 파이참이 되었을 뿐?) 마이페이지에서 내가 작성한 포스팅(유튜브쇼츠 공유)을 삭제하는 기능을 맡았다(수정은 다른 팀원이 맡음).
그러고도 빨리 끝나서(ㅋㅋㅋ) 전체 페이지 마크업을 다시 할까… css를 수정할까… 했지만 다른 팀원들이 계속 작업 중이었고 단순 스타일 변경을 위해 작업파일이 겹쳐서 merge하는 과정에 오류가 뜨면 민폐다 싶어 부족한 java와 python 공부를 했다.
Git
사실 코딩은 문제가 아니고 가장 큰 문제는 이놈의 git이었다ㅠㅠ
심지어 나는 이번에 git을 처음 써봤기 때문에(ㅋㅋㅋ) 어리둥절한 상태였다(다행히 항해에서 git강의를 배포해줬다.). 전에 SVN을 써보긴 헀지만(도대체 언제적이얔ㅋㅋ) 솔직히 개발팀장님이 뚝딱뚝딱 설치해준 걸 그냥 사용만 했기 때문에 하라는 것만 했지 기능을 전혀 몰랐다 ㅋㅋㅋ
그래서 작업할 때 브랜치를 나눠서 push하고 merge하고 해야 하는데 그냥 바로 main에 올려버려서 문제가 계속 발생(ㅋㅋㅋ)
심지어 팀원 중에 git 자체에 문제가 생겨서 pull을 했는데도 파일이 안 받아져… push를 했는데 반영이 안 돼… 패치를 여러번 시도해도 history 업데이트가 안 돼… 여러 복잡한 문제가 발생해서 협업이 쉽지 않구나 느꼈다 정말 ㅠㅠ
21 Jun 2022
역할분담
원대 (혼자 생각만 한)계획대로라면 웹퍼블리셔로 일했던 경험을 살려(ㅋㅋ) 간단하게 html마크업을 하고 파일을 뿌릴 생각이었으나 이미 팀원들이 작업을 시작하고 있어서(ㅋㅋ) 그냥 남은 걸 줏어서 코딩을 시작헀다…
코딩
1일차
나는 메인페이지를 맡았는데 디자인적 요소도 넣으면 좋겠다 싶어서 메인 상단에 유튜브에서 만든 유튜브쇼츠 홍보영상을 자동재생에 루프되게 하고 배경이미지처럼 깔았다.
gnb는 그 아래에 두고 스크롤을 내리면 fixed되게 했다. 뭐 늘 했던 그거라서 무감흥으로 작업했는데 팀원분들 반응이 괜찮아서 흡족했던 기억(ㅋㅋ)
기존에 사용했던 ajax로 get 받아서 append하기가 아니라 jinja2를 사용하라는 조건이 있어서 jinja2 사용하는 걸 찾아보느라 시간이 좀 걸렸다. 그래도 그 외적인 건 다 끝내둔 상태였기 떄문에 여유롭게 작업했다.
jinja2로 작업하라는 조건이 있었을 땐 헉 그건 또 뭐야 하고 쫄았는데(ㅋㅋ) 해보니까 오히려 파이썬으로 변수만 뿌려주면 html에서 받아서 출력해야 하는 부분에 넣기만 하면 되는 거라 쉬웠다.
그래서 작업 자체는 빨리 끝났는데 확인하는 과정에서 포스팅 페이지에서 reload로 index페이지에 왔을 때 db list가 바로 반영이 안 되는 문제가 생겼다!
원인 파악을 못해 어리둥절하고 있었는데 알고보니 값을 ajax로 html에서 뿌려주는 게 아니다보니 app.py에서 posting페이지에도 변수값을 줘야 했던 문제였다.
가슴이 철렁했는데 팀원이 금방 해결해서 무사히 넘어갔다.
20 Jun 2022
동북권 이노베이션캠프에 합격하고 시작된 1주차.
배정받은 팀원들과 4일동안(엄밀히 말하면 3.5일) 미니 웹 프로젝트를 시작하게 되었다.
주특기를 선택하고 첫 프로젝트라 바로 선택한 주특기를 활용해야 하나 긴장했는데, 아직 배운 게 없으므로 선택한 주특기에 상관 없이 Python으로 html을 코딩하는 프로젝트!
각자 선택한 프론트엔드/백엔드 상관 없이 기획한 미니 프로젝트를 협업해서 완성하는 것이 목표다.
기획
욕심은 첫 프로젝트인 만큼 나 이렇게 코딩 잘 한다는 걸 보여주고픈 마음이 없진 않았지만ㅋㅋ
3일동안 만들고 하루동안 테스트해서 제출하는 프로젝트라서 아주 간단한 사이트를 만들어야 했다.
기획단계에서 염두해둔 것들
- 간단한 사이트일 것
- 0주차에 받은 강의를 통해 얻은 지식 활용
- 구현할 수 있는 기능범위를 오버하지 않기
- 공지받은 필수 포함 사항 활용하기
1. 주제 정하기
주제를 정하기 위한 브레인스토밍을 하면서 팀원들의 관심사에 대해 이야기를 나눴고 구체적인 모습이 나온 게 2가지
- 나만의 커스텀 레시피
카페 커스텀메뉴나 서브웨이 꿀조합 같은 나만 알고 있는 레시피 조합을 공유하는 사이트
- 유튜브 쇼츠 공유
관심있는 유튜브 쇼츠를 공유하는 사이트
이 중에서 유튜브 쇼츠로 의견이 좁혀졌고, 배운 걸 어떻게 활용해서 사이트를 구성하면 좋을지까지 그려지면서 비교적 빨리 기획이 정해졌다.
2. 와이어프레임
구체적으로 클라이언트단에서 화면이 어떻게 보여질 것인가를 기획하는 것으로, 대화만으론 정해지기 어렵겠다 싶어 각자 와이어프레임을 구성해서 발표하기로 했다.
킹갓 그림판으로ㅋㅋ 열심히 그려서 발표를 했다. 그릴 땐 힘들었으나, 도형으로 그려두니까 보기 깔끔해서 좋았다.
(물론 두번다시는 하고 싶지 않지만)
그래도 결과적으로 보기에 깔끔해서 와이어프레임을 그리는 건 내가 하기로… 좋은 건진 모르겠지만ㅋㅋ
(다시 말하지만 두번다시는 하고 싶지 않다)
각자의 와이어프레임에서 비슷한 구성인 것은(예컨대 로그인/회원가입 폼같은) fix하고 메인이라든지 포스팅 페이지같은 건 발표된 시안에서 의견을 수렴하여 정했고 내가 다시 킹림판으로 그렸다…ㅋ
(다시 말하지만 두번다시는…이하생략)
와이어프레임
-
처음 냈던 와이어프레임
-
결정된 와이어프레임

마무리
프로젝트 이름은 Too Shorts로 정해졌다.
프로젝트명에 대해 얘기하다가 유튜브 쇼츠들이니까 many의 의미 + 강조의 의미해서 무지성으로 던졌는데 딱히 더 좋은 아이디어가 나오지 않아 그냥 정해졌다.
쇼츠니까 예전 슉슈슈슉 밈을 활용한 아이디어도 제시되었고 참신했지만 너무 길다는 이유로(ㅋㅋ) 제외되었다…
점심 먹고 와이어프레임을 그려서 제출하고, 협업을 위한 Git설치 및 GitHub 가입(그렇다 이날 처음 깃헙 가입을 했다ㅋㅋ)을 하고 팀장님이 만든 리포에 초대받고, 제출 하라는 거 뚝딱뚝딱하고 강의영상 보다가 면담 호출받고 매니저님과 대화하다가 하루가 끝났다.
내일 역할분담 및 코딩이 시작될텐데 기대 반 걱정 반이다. 다른 팀원들에 비해 내가 개발 지식이 많이 부족해서ㅠㅠ 빨리 따라잡도록 해야겠다.
Too Shorts GitHub