Как вернуть массив JSON с помощью Bottle?
Я пишу API, используя Bottle, который до сих пор был фантастическим. Тем не менее, я столкнулся с небольшим препятствием при попытке вернуть массив JSON. Здесь мой тестовый код приложения:
from bottle import route, run
@route('/single')
def returnsingle():
return { "id": 1, "name": "Test Item 1" }
@route('/containsarray')
def returncontainsarray():
return { "items": [{ "id": 1, "name": "Test Item 1" }, { "id": 2, "name": "Test Item 2" }] }
@route('/array')
def returnarray():
return [{ "id": 1, "name": "Test Item 1" }, { "id": 2, "name": "Test Item 2" }]
run(host='localhost', port=8080, debug=True, reloader=True)
Когда я запускаю это и запрашиваю каждый маршрут, я получаю ответы JSON, которые я ожидаю от первых двух маршрутов:
/один
{ id: 1, name: "Test Item 1" }
/containsarray
{ "items": [ { "id": 1, "name": "Test Item 1" }, { "id": 2, "name": "Test Item 2" } ] }
Итак, я ожидал вернуть список словарей, чтобы создать следующий ответ JSON:
[ { "id": 1, "name": "Test Object 1" }, { "id": 2, "name": "Test Object 2" } ]
Но запрос маршрута /array
приводит к ошибке. Что я делаю неправильно, и как я могу вернуть массив JSON таким образом?
Ответы
Ответ 1
Плагин JSON для бутылок ожидает, что будут возвращены только dicts, а не массивы. Есть уязвимости, связанные с возвратом массивов JSON - см., Например, этот пост об угоне JSON.
Если вам действительно нужно это сделать, это можно сделать, например.
@route('/array')
def returnarray():
from bottle import response
from json import dumps
rv = [{ "id": 1, "name": "Test Item 1" }, { "id": 2, "name": "Test Item 2" }]
response.content_type = 'application/json'
return dumps(rv)
Ответ 2
Согласно документации Bottle 0.12:
Как упоминалось выше, словари Python (или их подклассы) автоматически преобразуется в строки JSON и возвращается к браузер с заголовком Content-Type, установленным в application/json. Эта упрощает реализацию json-based API. Форматы данных, отличные от json также поддерживаются. Дополнительную информацию см. В уроке-выходе-фильтра.
Это означает, что вам не нужно import json
и не устанавливать атрибут content_type ответа.
Таким образом, код становится значительно уменьшенным:
@route('/array')
def returnarray():
rv = [{ "id": 1, "name": "Test Item 1" }, { "id": 2, "name": "Test Item 2" }]
return dict(data=rv)
И документ JSON, возвращенный веб-сервером, будет выглядеть так:
{"data": [{"id": 1, "name": "Test Item 1"}, {"id": 2, "name": "Test Item 2"}]}