코딩하는 털보

21.09.17 TIL 본문

Diary/Today I Learned

21.09.17 TIL

이정인 2021. 9. 17. 17:45

항해99 DAY 5

오늘은 미니 프로젝트 마감일이다.

진행 중 어려웠던 것들

Response(), jsonify(), render_template()
스프링을 할 때도 그렇지만 View에 리스폰스를 제공할 때 이런 여러가지 메서드들 때문에 골치가 아프다.
하나로 통일하자니 실제 동작시 어려움이 많았다. 이 부분은 내가 조원들에게 소통을 더 많이했다면 나았을까 싶다.

  • jsonify() 메서드는 response를 보내기 위해 아규먼트들을 json 타입으로 만드는 메서드이다. Response 타입 객체를 반환한다.
    때문에 Rest API에서는 이 메서드를 많이 사용하지 않을까 예상한다.
  • render_template() 메서드는 매칭되는 html 파일을 전달해준다.
    스프링에서 @ResponseBody가 아닌 기본적인 핸들러들이 return 값을 통해 view를 매핑해줬던 것과 유사하다.
    model을 담아서 view에 전달하는 것 까지 이 메서드 하나로 처리할 수 있다.
  • Response()
    나는 이 메서드를 비동기 통신에 사용하였다. 특히 예외를 처리할때..
    response에 메시지와 상태 코드를 담아서 넘겨주고 프론트에서 얼럿으로 메시지를 사용자에게 전달해주는 식으로 만들었다.
    jsonify과 마찬가지로 Response 타입 객체를 반환한다.
    그런데 다음날 보니... 나는 왜 파이썬에도 객체가 있다는 것을 간과하고 있었을까. 이건 메서드가 아니고 Response 클래스의 생성자였다.
    jsonify는 Response 객체를 생성하고 반환하는 메서드이다. 아마도 jsonify에서도 내부적으로 이 생성자를 사용할 듯 하다.
    결국 jsonify()와 Response 생성자는 둘 다 Response 객체를 반환한다.

이렇게 쓰고나니 머릿속에 조금은 가닥이 잡힌다. 그냥 정리 먼저할껄
다음주 부터는 스프링을 사용한 프로젝트를 진행할 듯 한데 그땐 요부분 한번더 정리하자.

MongoDB
나는 NoSQL을 항해99에서 처음 접해본다.
처음에는 테이블(컬렉션..anyway)에 리스트가 포함되어 있는 것이 (RDB에서는 ORM으로 매핑을 해주어야 하는 상속 관계) 너무 싱기방기해서 게시글 도메인에 좋아요든 댓글이든 다 리스트로 담으려고 했다.
근데 컬렉션 내부의 리스트에는 자동으로 ID가 들어가지 않는다는 것을 알고는 다 분해해버렸다.
사실 당연히 NoSQL 보다는 RDM가 적합한 서비스였기 때문이긴 하지만 좀아쉬웠다. (Nosql이 비정형 데이터에 유리하다는데 한편 드는 생각은 그래서 비정형 데이터가 가져오는 이점은 무엇이며 기술블로그들에는 왜 다들 정의만 해놓고 직접적인 예시는 들지 못했는가...)

MongoDB의 도큐먼트 ID는 ObjectId 타입이다 항해99 질문방에 이 타입에 대한 질문이 여러번나왔다.
ObjectId가 문자열이 아니기 때문에 예상과 다른 오류들이 발생한 것 같다. (특히 jsonify() 인것 같다.)
ObjectId를 리스펀스로 넘기기 전에 문자열로 바꾸는 우회법을 사용한다.

comment["_id"] = str(comment["_id"])

일단 자바와 달리 특정 변수에 대한 정해진 타입이 없기때문에 (var...anyway) 이런 코딩이 가능하다는게 매우 놀랍다.
나처럼 자바만 아는 사람이 이 문장을 보면 이렇게 생각할 듯 하다.
"comment의 _id가 ObjectId 타입이라며, 근데 왜 문자열을 집어넣는거여?"
다시 한번 파이썬은 자바와 달리 특정 변수에 대한 정해진 타입이 없다. 그래서 위와 같이 실행하면 comment의 _id는 그냥 문자열로 바뀐다.

사실 이 우회법은 내 생각에는 조금 부자연스럽다.
MongoDB에는 분명히 comment의 _id에 ObjectId(str)처럼 들어가 있다.
프론트에서 받아서 사용할 comment의 _id가 이 ObjectId(str)와 과연 같은가.
같다고 생각할 수도 있다 어차피 프론트엔드에서 받는 _id는 이 ObjectId(str)들을 분류하는 유일한 값이니까.
그러나 그 쓰임이 같을 수는 없다고 생각한다. 문자열은 문자열 역할만 할뿐 ObjectId의 역할을 할 수 없다. 반대도 그렇다.
(요청에서 받아온 _id는 다시 ObjectId(_id)로 만들어야 제대로 사용할 수 있는것 처럼.)

comment["comment_id"] = str(comment["_id"])

이렇게 했으면 어땠을까 사실 별로 다른지 모르겠다.
변수만 봐도 "야 내가 너한테 줄라고 ObjectId에서 문자열로 변환해서 넣어놨어"라는 의미를 전달할 수 있다면 좋을 것 같다.
근데 지금 당장은 생각이 안남.
한편 ObjectId가 jsonify의 아규먼트가 될 수 없는 이유는 한번 찾아봐야 될 것 같다.

MongoDB의 쿼리 메서드들은 잘 추상화되어있다.
난 이번 프로젝트에서 모든 메서드를 사용할 때 아래처럼 사용했다.
db.likes.update_one({"post_id": post_id_receive, "user_id": user["user_id"]}, {"$set": {"like": -1}})
싫다 이런 길고 보기어려운 줄. 처음이니까 한번은 넘어가고 담에 mongoDB 또쓴다면 이렇게 해보자.

query = {
  "post_id": post_id_receive, 
  "user_id": user["user_id"]
}
projection = {
  {"$set": {"like": -1}}
}
db.collection.find(query, projection)

깰꼼쓰

우리 조의 프로젝트는 아래와 같이 설계했다.

페이지 설계

  • 메인 페이지

    1. 전체 재판 목록 확인
      • 최근에 저장된 재판 순으로 전체 재판 목록 확인
      • 목록의 오른쪽 끝에서 해당 재판의 공감 수를 확인
      • 클릭하면 해당 재판의 상세 페이지로 이동
      • 한 페이지에 7개 씩 출력
    2. 재판 저장
      • 로그인하지 않았으면 얼럿 띄우기
    3. 오늘의 TOP3 / 이번 주 TOP3
      • 오늘 또는 한 주간의 재판 중 공감 수가 높은 순으로 각 3개 확인
  • 재판 상세 페이지

    1. 재판 상세 내용 확인
      • 재판의 제목, 내용, 작성자, 작성 시간, 조회 수, 공감 수, 비공감 수, 댓글, 댓글 수를 확인
    2. 재판 수정과 삭제
      • 재판의 작성자가 아니면 얼럿 띄우기
    3. 공감과 비공감
      • 공감 또는 비공감 중복 선택 불가
      • 두번 이상 선택 불가
    4. 댓글
      • 댓글을 작성하고 목록을 확인
      • 댓글 목록에는 댓글의 내용, 작성자, 작성 시간을 확인할 수 있음
      • 댓글의 작성자만 댓글을 삭제할 수 있음
  • 재판 수정 페이지

    1. 재판의 제목 또는 내용을 수정
  • 마이 페이지

    1. 내가 작성한 재판 및 댓글 목록 확인
      • 최근에 저장된 글 순으로 목록 확인
      • 작성한 재판 목록의 오른쪽 끝에서 해당 재판의 공감 수를 확인
      • 작성한 댓글 내용과 어떤 제목의 재판에 달렸는 지 확인
      • 클릭하면 해당 재판의 상세 페이지로 이동
      • 한 페이지에 10개 씩 출력
  • 로그인 페이지

    1. 로그인 또는 회원가입
  • 에러 페이지

    1. 잘못된 URL로 접근 시 404 페이지
    2. 토큰 시간이 만료되거나 토큰 정보가 잘못되어 있으면 401 페이지

API

기능 URL Method Request Response
로그인 POST /login
회원가입 POST /register
{
user_id: user_name,
pw: password
}
회원가입 중복 확인 POST /register/check_dup
{
username_give: username
}
게시글 목록 리뷰 GET /posts 전체 게시글 목록
게시글 상세 내용 GET /post 해당 게시글 Objectid, 게시글 DB
게시글 작성 POST /post
{
title: title,
content: comment,
image: ''
}
조회수 증가 POST /view
{
post_id: id
}
댓글 작성 POST /post
{
post_id: button_value,
comment: reply,
create_date: Today
}
게시글 삭제 DELETE /post
{
post_id: PostID
}
공감 비공감 이벤트 POST /like
{
post_id: button_id,
action: button_action
}
댓글 제거 DELETE /comment
{
post_id: PostID,
comment_id: CommentID
}
게시판 수정 PUT /post
{
post_id: PostID,
title: PostTitle,
content: PostContent,
image: PostImage
}
Comments