Python
responder

responderでjsonを返す際に日本語をUnicodeエスケープさせない

※ 訂正

文字化けではなく、Unicodeエスケープが正しい表現です。

コメント欄をご確認ください。

記事内容を修正予定ではありますが、取り急ぎ。


記事概要

responder on dockerしようとしたら、hello worldできなくて焦った話 に引き続き、responderです。

プロ野球選手の名前をjsonで返すAPIを実装した際に、日本語のUnicodeエスケープを解消したチップスです。


ドキュメントに沿って実装したけど、Unicodeエスケープされた

https://python-responder.org/en/latest/quickstart.html#returning-json-yaml


実装

result[0] = {'name': '淺間 大基'}

resp.media = result[0]


ブラウザでの表示

スクリーンショット 2019-01-21 9.57.50.png

やっぱりこういう時、日本人だなーって思いますね :sushi:


解消方法


実装

resp.headers = {"Content-Type": "application/json; charset=utf-8"}

resp.content = json.dumps(result[0], ensure_ascii=False)


ブラウザでの表示

スクリーンショット 2019-01-21 10.02.16.png

上記で良いと思うのですが、いかがでしょうか。


responseクラスに関して

ようするに、


  • asciiに限定したエンコードをしない

  • jsonに変換する

  • Content-Typeのcharset=utf-8

を満たす実装が必要なわけです。

responseクラスの実装を見た感じだと、先程示した実装で良いと思うですがいかがでしょうか。

https://python-responder.org/en/latest/_modules/responder/models.html#Response

class Response:

__slots__ = [
"req",
"status_code",
"text",
"content",
"encoding",
"media",
"headers",
"formats",
"cookies",
"session",
]

def __init__(self, req, *, formats):
self.req = req
self.status_code = None #: The HTTP Status Code to use for the Response.
self.text = None #: A unicode representation of the response body.
self.content = None #: A bytes representation of the response body.
self.encoding = DEFAULT_ENCODING
self.media = (
None
) #: A Python object that will be content-negotiated and sent back to the client. Typically, in JSON formatting.
self.headers = (
{}
) #: A Python dictionary of ``{key: value}``, representing the headers of the response.
self.formats = formats
self.cookies = {} #: The cookies set in the Response, as a dictionary
self.session = (
req.session.copy()
) #: The cookie-based session data, in dict form, to add to the Response.

@property
async def body(self):
if self.content is not None:
return (self.content, {})

if self.text is not None:
return (self.text.encode(self.encoding), {"Encoding": self.encoding})

for format in self.formats:
if self.req.accepts(format):
return (await self.formats[format](self, encode=True)), {}

# Default to JSON anyway.
return (
await self.formats["json"](self, encode=True),
{"Content-Type": "application/json"},
)

async def __call__(self, receive, send):
body, headers = await self.body
if self.headers:
headers.update(self.headers)

response = StarletteResponse(
body, status_code=self.status_code, headers=headers
)
await response(receive, send)

以上。問題あればご指摘ください!