flask jsonify 와 json.dumps의 차이

yeeun lee·2020년 6월 2일
11

flask

목록 보기
2/5

flask 책에서 jsonify를 사용해서 그대로 따라 썼는데, 왜 쓰는지에 대해 이해하기 위해 찾아보았다. 내가 이해한 바로 결론을 내면, jsonify가 편하긴 하지만 지원되지 않는 형식(한글 등)을 주고 받으려면 별도의 인코더가 필요하다!

참고 문서:
- flask API
- programmerssought
- soooprmx

1. flask Response 보내는 방법

1.1 jsonify

사용자가 json data를 내보내도록 제공하는 flask의 함수. jsonify()는 json response를 보내기 위해 이미 content-type header가 'application/json'로 되어 있는 flask.Response() 객체를 리턴한다.

문제 (참고 링크)

jsonify는 json.dump를 사용하기 때문에 아스키 이스케이프 인코딩을 적용한다. Flask처럼 웹서버로 쓰이는 환경에서 이런식으로 데이터를 내려보내면 프론트엔드에서는 다시 이 코드포인트들을 문자열로 변환해야 한다는 문제점이 생긴다.

- jsonify soure code

플라스크 소스 코드의 일부분을 참고해보자. 위에서 잠깐 언급했듯 jsonify도 함수 내부에서도 json form으로 serialize하는 과정에서 json.dumps를 쓴 것을 알 수 있다. 다만 dump하기 전에 받은 값들을 모두 dictionary로 만들었다.

def jsonify(*args, **kwargs):
    if __debug__:
        _assert_have_json()
    return current_app.response_class(json.dumps(dict(*args, **kwargs),
        indent=None if request.is_xhr else 2), mimetype='application/json')

1.2 json.dumps

python이 가지고 있는 json library의 json.dumps() method는 수동으로 MIME type header를 추가해주어야 하는 encoded string을 리턴한다.

하지만 flask가 알아서 판단해 response를 자동으로 보내주도록 사용하기 때문에 직접적으로 사용할 수 있다. 다만 reponse header fields는 디폴트(text/html; charset=utf-80)로 처리된다.

1.3 dictionary

아래에 있는 Flask API 설명에 의하면, payload serializer가 있고, 디폴트가 compact JSON이라서 바로 가지는 것 같다.

serializer = <flask.json.tag.TaggedJSONSerializer object>

A python serializer for the payload. The default is a compact JSON derived serializer with support for some extra Python types such as datetime objects or tuples.

2. 차이점

2.1 Content type

  • jsonify : application/json
  • json.dumps : text/html; charset=utf-8
  • return 값을 dictionary로 했을 경우 : application/json
# jsonify
return jsonify({'token' : token}), 200

# json.dumps
return json.dumps({'token' : token}), 200

# dictionary
return {'token' : token}, 200

2.2 Parameter accepted

  • jsonify : 참고한 글에서는 dictionary type만 된다고 적혀 있는데, 테스트를 해보니 이제 리스트도 받을 수 있다. 아마 업데이트가 된 것 같다.

  • json.dumps : jsonify 보다 더 다양한 type을 받을 수 있다고 나와있다.

2.3 function call

이건 내가 python shell에서 찾다가 본 사소한 차이점인데 ㅋㅋ 당연한 말이겠지만 jsonify는 flask 앱 내에서만 실행이 가능해서 앱 세팅이 안 되어 있는 shell에서는 사용이 안 된다.
반면 json.dumps는 shell에서 바로 return을 받아볼 수 있다.

2.4 실험

- return [ ]

view function은 string, dict, tuple, reponse instange(jsonify 같은?) 애들만 return 할 수 있다. 글 하단에 공식 문서의 response type을 첨부해두었다. 우선 리스트를 리턴하려고 했을 때 뜨는 에러는 다음과 같다.

TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple,
Response instance, or WSGI callable, but it was a list.

만약 json.dumps, jsonify로 리스트를 보내게 되면 정상적으로 들어온다. 위에서 말했듯 content-type만 다르다.

...
return json.dumps( [ token ] )
return jsonify( [ token ] )
# 둘 다 리스트를 리턴할 수 있다.

3. 결론

  • jsonify를 쓰나, 그냥 딕셔너리로 반환하나 큰 차이는 없다.
  • 다만 jsonify는 일부 형식을 못 반환할 수 있어, encoder를 사용해주어야 한다.

4. flask reponse 형식

아래 링크의 make_response에서 확인했다.
https://flask.palletsprojects.com/en/1.1.x/api/

  1. make_response(rv)
    Convert the return value from a view function to an instance of response_class.

  2. Parameters rv –
    the return value from the view function. The view function must return a response. Returning None, or the view ending without returning, is not allowed. The following types are allowed for view_rv:

  3. str (unicode in Python 2)
    A response object is created with the string encoded to UTF-8 as the body.

  4. bytes (str in Python 2)
    A response object is created with the bytes as the body.

  5. dict
    A dictionary that will be jsonify’d before being returned.

  6. tuple
    Either (body, status, headers), (body, status), or (body, headers), where body is any of the other types allowed here, status is a string or an integer, and headers is a dictionary or a list of (key, value) tuples. If body is a response_class instance, status overwrites the exiting value and headers are extended.

  7. response_class
    The object is returned unchanged.

  8. other Response class
    The object is coerced to response_class.

  9. callable()
    The function is called as a WSGI application. The result is used to create a response object.

profile
이사간 블로그: yenilee.github.io

2개의 댓글

comment-user-thumbnail
2020년 6월 2일

멋져...

답글 달기
comment-user-thumbnail
2020년 6월 24일

멋있어...

답글 달기