깔끔한 파이썬 탄탄한 백엔드 - 5장

Jajuna_99·2022년 6월 11일
0

5장 본격적으로 API 개발하기

  • 회원가입
  • 트윗(tweet)
  • 다른 회원 팔로우(follow)하기
  • 다른 회원 언팔로우(unfollow)하기
  • 타임라인
  • 트위터의 기능들을 모방해서 만드는 토이 프로젝트이고, 트위터에 비해 한참 모자르지만 백엔드 입문, 비지니스 로직 작성하는데는 무리가 없을 것이다.

    회원가입

    app.users = {}
    app.id_count = 1
    
      @app.route("/sign-up", methods=['post'])
      def sign_up():
          new_user = request.json
          new_user["id"] = app.id_count
          app.users[app.id_count] = new_user
          app.id_count = app.id_count + 1
    
          return jsonify(new_user)

    회원가입의 필요한 사용자의 이름, 이메일, 아이디, 비밀번호, 프로필 등을 구현했다.

    • users : dictionary 자료형 변수에 새로 가입한 사용자를 저장
    • id_count : 사용자의 id 값을 저장하는 변수, 1부터 차례로 증가할 것이다.
      *이렇게 설정하면 동시 요청이 많아졌을 때 오류가 날 수 있다. atomic increment operation을 사용해야 한다.
    • 데코레이터를 사용해 엔트포인트 정의, HTTP 메소드는 post를 사용
    • new_user = request.json : HTTP 요청을 통해 전송된 회원 정보를 읽어 들인다. request는 엔드포인트에 전송된 HTTP 요청 정보를 저장하고 있다. 이를 JSON 데이터를 dictionary 형태로 변환했다.
    • new_user["id"] = app.id_count : HTTP 요청으로 전송된 회원가입 정보에 id 값을 더하여 준다.
    • app.id_count = app.id_count + 1 : id_count 1 추가
    • return jsonify(new_user) : 회원가입한 사용자의 정보를 JSON 형태로 전송.

    트윗(tweet)

    app.tweets = []
    
      @app.route("/tweet", methods=['POST'])
      def tweet():
          payload = request.json
          user_id = int(payload['id'])
          tweet = payload['tweet']
    
          if user_id not in app.users:
              return '사용자가 존재하지 않습니다.', 400
    
          if len(tweet) > 300:
              return '300자를 초과 했습니다.', 400
    
          user_id = int(payload['id'])
    
          app.tweets.append({
              'user_id' : user_id,
              'tweet' : tweet
          })
    
        return '', 200 
    • app.tweets = [] : 사용자들의 트윗들을 저장할 티렉터리, key는 사용자 아이디, value는 사용자들의 트윗을 담고 있는 리스트다.
    • tweet = payload['tweet'] : HTTP 요청으로 전송된 JSON 데이터에서 "tweet" 필드를 읽어 들여 사용자의 tweet 내용이 300자를 넘었는지 확인
    • 사용자 존재 여부, 300자 초과 확인을 해서 400 bad request 응답을 보낸다.
    • user_id = int(payload['id']) : HTTP 요청으로 전송된 JSON 데이터에서 사용자 아이디를 읽어 들인다.
    • app.tweets.append({
      'user_id' : user_id,
      'tweet' : tweet
      }) : 해당 사용자 아이디와 트윗을 딕셔너리(dictionary)로 생성해서 app.tweets 리스트에 저장시킨다.

    이하 밑에 API 설명은 생략하겠다. 소스코드 보고 직접 생각해보고 실습해보자.

    다른 회원 팔로우(follow)하기

    @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)
    

    위와 같이 실행하면, 사용자 아이디들을 저장하는 자료구조로 set을 json 모듈이 JSON으로 변경 할 수 없어 오류가 날 것이다. (list는 가능하다.)

    그래서 커스텀 JSON 엔코더(custom JSON encoder)를 만들어서 디폴트 JSON 엔코더(default JSON encoder)에 덮어 씌울 것이다.

    from flask.json import JSONEncoder
    
    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 : flask.json 모듈에서 JSONEncoder 클래스를 import
    • class CustomJsonEncoder(JSONEncoder): JSONEncoder 클래스를 부모 클래스로 상속받는 CustomJSONEncoder 클래스를 정의
    • def default(self, obj) : JSONEncoder 클래스의 default 메소드를 확장(overwrite_gksek.
    •     if isinstance(obj, set):
              return list(obj)
      *만약 객체(obj)가 set인 경우 list로 변경해서 리턴
    • return JSONEncoder.default(self, obj) : 만약 set이 아닌 경우는 본래 JSONEncoder 클래스의 default 메소드를 호출해서 리턴
    • app.json_encoder = CustomJsonEncoder : 작성해준 Custom Encoder를 디폴트 Encoder로 지정해 준다. 이러면 jsonify 함수가 호출될 때마다 이 Encoder 실행된다.

    다른 회원 언팔로우(unfollow)하기

    @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)

    타임라인

    @app.route('/timeline/<int:user_id>', methods=['GET'])
    def timeline(user_id):
        if user_id not in app.users:
            return '사용자가 존재하지 않습니다.', 400
    
        follow_list = app.users[user_id].get('follow', set())
        follow_list.add(user_id)
        timeline = [tweet for tweet in app.tweets if tweet['user_id']in follow_list]
    
        return jsonify({
            'user_id' : user_id,
            'timeline' : timeline
        }) 

    5장 요약

    Flask와 파이썬 문법들을 사용해 좀 그럴듯한 미니터 API들을 구현해봤습니다.

    각 API들을 저번 포스트에서 해봤던 것처럼 httpie 테스트 해보는 것을 추천

    제 깃헙을 참고해서 작성했습니다.

    profile
    Learning bunch, mostly computer and language

    0개의 댓글