전송할 JSON 데이터는 아래와 같다.
{
"id" : 1,
"follow" : 2
}
{
"id" : 1,
"unfollow" : 2
}
id 필드는 해당 사용자의 아이디이고, follow/unfollow 필드는 언팔로우하고자 하는 사용자의 아이디이다.
먼저 팔로우 엔드포인트부터 구현해본다.
@app.route('/follow', methods=['POST'])
def follow():
payload = request.json
user_id = int(payload['id'])
user_id_to_follow = int(payload['follow'])
if user_id not in app.users or user_id_to_follow not in app.users:
return '유저가 존재 하지 않습니다', 400
user = app.users[user_id]
user.setdefault('follow', set()).add(user_id_to_follow)
return jsonify(user)
user_id = int(payload['id'])
: HTTP 요청으로 전송된 JSON 데이터에서 해당 사용자의 아이디를 읽어 들인다.
user_id_to_follow = int(payload['follow'])
: HTTP 요청으로 전송된 JSON 데이터에서 해당 사용자가 팔로우할 사용자의 아이디를 읽어 들인다.
if user_id not in app.users or user_id_to_follow not in app.users:
return '유저가 존재 하지 않습니다', 400
: 만일 해당 사용자나 팔로우할 사용자가 존재하지 않는다면 400 Bad Request 응답을 보낸다.
user = app.users[user_id]
: app.users 딕셔너리에서 해당 사용자 아이디를 사용해서 해당 사용자의 데이터를 읽어 들인다.
user.setdefault('follow', set()).add(user_id_to_follow)
: 4번에서 읽어 들인 사용자의 정보를 담고 있는 딕셔너리가 이미 "follow"라는 필드를 가지고 있다면, 즉 이미 사용자가 다른 사용자를 팔로우한 적이 있다면, 사용자의 "follow" 키와 연결되어 있는 set에 팔로우하고자 하는 사용자 아이디를 추가한다.
만일 처음 다른 사용자를 팔로우 하는 것이라면 사용자의 정보를 담고 있는 딕셔너리에 "follow"라는 키를 empty set과 연결하여 추가한다.
팔로우 엔드포인트를 구현할 때 해당ㅇ 사용자가 팔로우하는 다른 사용자들의 아이디를 저장하는 자료구조로써 set을 사용한다.
서버를 실행시켜서 팔로우 엔드포인트에 HTTP 요청을 보내도록 하자
(id가 2개 필요하므로 회원가입 엔드포인트를 2번 실행시켜서 id를 2번까지 만들어줘야 한다.)
명령어를 실행시키면 위와 같은 서버 에러가 뜨게 되는데
이유는 팔로우하는 사용자 아이디들을 저장하는 자료구조로 사용하는 set을 파이썬의 json 모듈이 JSON으로 변경하지 못하기 때문이다.
list는 JSON으로 변경될 수 있지만 set은 변경하지 못하므로 오류가 난다.
이 문제를 해결하기 위해 커스텀 JSON 엔코더(custom JSON encoder)를 구현해서 디폴트 JSON 엔코더에 덮어 써야한다.
from flask.json import JSONEncoder
## Default JSON encoder는 set를 JSON으로 변환할 수 없다.
## 그러므로 커스텀 엔코더를 작성해서 set을 list로 변환하여
## JSON으로 변환 가능하게 해주어야 한다.
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
return JSONEncoder.default(self, obj)
app.json_encoder = CustomJSONEncoder
from flask.json import JSONEncoder
class CustomJSONEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return JSONEncoder.default(self, obj)
app.json_encoder = CustomJSONEncoder
위의 코드를 추가하고 시스템을 재시작시킨 후 "follow" 엔드포인트를 호출하면 정상적으로 HTTP 응답이 오게 된다.
이제 언팔로우 엔드포인트를 구현해본다.
@app.route('/unfollow', methods=['POST'])
def unfollow():
payload = request.json
user_id = int(payload['id'])
user_id_to_follow = int(payload['unfollow'])
if user_id not in app.users or user_id_to_follow not in app.users:
return '유저가 존재 하지 않습니다', 400
user = app.users[user_id]
user.setdefault('follow', set()).discard(user_id_to_follow)
return jsonify(user)
user_id_to_follow = int(payload['unfollow'])
: 언팔로우할 사용자 아이디를 HTTP 요청으로 전송된 데이터에서 읽어 들인다.
if user_id not in app.users or user_id_to_follow not in app.users:
: 팔로우 엔드포인트와 마찬가지로 해당 사용자 아이디 혹은 언팔로우할 사용자 아이디가 존재하지 않으면 400 Bad Request 응답을 보낸다.
user.setdefault('follow', set()).discard(user_id_to_follow)
: 언팔로우하고자 하는 사용자 아이디를 set에서 삭제한다.
깔끔한 파이썬 탄탄한 백엔드 / 저자: 송은우