IntegerField() 在 JSON 中转换为任意数字的字符串
IntegerField() is converted to string in JSON for any number
这道题和this one非常相似,只是更糟...在我的测试中,即使是像1
这样的小整数也会被转换成字符串。这是我的 MWE:
app.yaml
application: your-app-id
version: 1
runtime: python27
threadsafe: true
api_version: 1
handlers:
- url: /_ah/spi/.*
script: example.app
secure: always
libraries:
- name: endpoints
version: 1.0
example.py
import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
package = 'Example'
class Number(messages.Message):
number = messages.IntegerField(1)
@endpoints.api(name='example', version='v1')
class ExampleApi(remote.Service):
@endpoints.method(message_types.VoidMessage, Number,
path = "getNumber", http_method='GET', name = 'getNumber')
def get_number(self, _):
return Number(number = 3) # This is a small integer. Isn't?
app = endpoints.api_server([ExampleApi])
测试
$ curl http://localhost:8080/_ah/api/example/v1/getNumber
{
"number": "3"
}
为什么?不应该是 { "number": 3 }
吗?如果我想对它们进行算术运算,这迫使我在客户端重新转换所有整数。
(使用 GAE SDK 版本 1.9.21 - 2015-05-12
进行测试,在 Linux 和 OSX 中均使用 "native" dmg。编辑 :也在生产中测试,部署在 GAE 服务器中,结果相同......整数作为字符串接收)
更新
即使我的简单示例 returns 整数作为字符串(如上所示),Google 自己的 API 也不会那样做。他们做正确的事。例如,通过 API 浏览器使用 books api
,此处:
https://apis-explorer.appspot.com/apis-explorer/#p/books/v1/books.volumes.list?q=Google&_h=8&
你得到一个 JSON 答案,其中包含正确编码的整数,例如:
{
"kind": "books#volumes",
"totalItems": 551,
"items": [ ... ]
...
}
所以他们的 API 返回良好 json。为什么我的 API 使用相同的工具(或者可能不是?)返回整数而不是字符串?我认为这是一个错误。
看起来 IntegerField 的默认变体是 INT64,它被编码成 EndpointsProtoJson.encode_field
中的字符串
def encode_field(self, field, value):
"""Encode a python field value to a JSON value.
Args:
field: A ProtoRPC field instance.
value: A python value supported by field.
Returns:
A JSON serializable value appropriate for field.
"""
if (isinstance(field, messages.IntegerField) and
field.variant in (messages.Variant.INT64,
messages.Variant.UINT64,
messages.Variant.SINT64)):
if value not in (None, [], ()):
if isinstance(value, list):
value = [str(subvalue) for subvalue in value]
else:
value = str(value)
return value
您可以通过在 messages.Message
子类中将其指定为 32 位整数来更改此行为。
class Number(messages.Message):
number = messages.IntegerField(1, variant=messages.Variant.INT32)
这道题和this one非常相似,只是更糟...在我的测试中,即使是像1
这样的小整数也会被转换成字符串。这是我的 MWE:
app.yaml
application: your-app-id
version: 1
runtime: python27
threadsafe: true
api_version: 1
handlers:
- url: /_ah/spi/.*
script: example.app
secure: always
libraries:
- name: endpoints
version: 1.0
example.py
import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
package = 'Example'
class Number(messages.Message):
number = messages.IntegerField(1)
@endpoints.api(name='example', version='v1')
class ExampleApi(remote.Service):
@endpoints.method(message_types.VoidMessage, Number,
path = "getNumber", http_method='GET', name = 'getNumber')
def get_number(self, _):
return Number(number = 3) # This is a small integer. Isn't?
app = endpoints.api_server([ExampleApi])
测试
$ curl http://localhost:8080/_ah/api/example/v1/getNumber
{
"number": "3"
}
为什么?不应该是 { "number": 3 }
吗?如果我想对它们进行算术运算,这迫使我在客户端重新转换所有整数。
(使用 GAE SDK 版本 1.9.21 - 2015-05-12
进行测试,在 Linux 和 OSX 中均使用 "native" dmg。编辑 :也在生产中测试,部署在 GAE 服务器中,结果相同......整数作为字符串接收)
更新
即使我的简单示例 returns 整数作为字符串(如上所示),Google 自己的 API 也不会那样做。他们做正确的事。例如,通过 API 浏览器使用 books api
,此处:
https://apis-explorer.appspot.com/apis-explorer/#p/books/v1/books.volumes.list?q=Google&_h=8&
你得到一个 JSON 答案,其中包含正确编码的整数,例如:
{
"kind": "books#volumes",
"totalItems": 551,
"items": [ ... ]
...
}
所以他们的 API 返回良好 json。为什么我的 API 使用相同的工具(或者可能不是?)返回整数而不是字符串?我认为这是一个错误。
看起来 IntegerField 的默认变体是 INT64,它被编码成 EndpointsProtoJson.encode_field
def encode_field(self, field, value):
"""Encode a python field value to a JSON value.
Args:
field: A ProtoRPC field instance.
value: A python value supported by field.
Returns:
A JSON serializable value appropriate for field.
"""
if (isinstance(field, messages.IntegerField) and
field.variant in (messages.Variant.INT64,
messages.Variant.UINT64,
messages.Variant.SINT64)):
if value not in (None, [], ()):
if isinstance(value, list):
value = [str(subvalue) for subvalue in value]
else:
value = str(value)
return value
您可以通过在 messages.Message
子类中将其指定为 32 位整数来更改此行为。
class Number(messages.Message):
number = messages.IntegerField(1, variant=messages.Variant.INT32)