Pretty-print format all JSON response bodies
Flask-RESTful automatically converts a response body to JSON when it creates the Response object. The Flask app configuration option RESTFUL_JSON is added by this commit to appropriately modify how the JSON body is constructed. response_filter has been modified so that it returns a tuple of information that Flask-RESTful will use to create an appropriately formatted response. Resource.error_response is creating the Response object itself and so has been modified to format the JSON in the same way as Flask-RESTful. Ideally, error_response would not create a separate Response object however addressing this is a separate issue. Change-Id: I02eafaf48d7c6e2ceab0add2f78cf6aa1b890f18 Closes-bug: 1664328
This commit is contained in:
parent
7258e8e739
commit
0f7ee6d791
|
@ -1,6 +1,7 @@
|
|||
from datetime import date
|
||||
import os
|
||||
from paste import deploy
|
||||
from flask import Flask
|
||||
from flask import Flask, json
|
||||
|
||||
|
||||
from oslo_config import cfg
|
||||
|
@ -48,10 +49,27 @@ def create_app(global_config, **local_config):
|
|||
return setup_app()
|
||||
|
||||
|
||||
class JSONEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, o):
|
||||
if isinstance(o, date):
|
||||
return o.isoformat()
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
RESTFUL_JSON = {
|
||||
"indent": 2,
|
||||
"sort_keys": True,
|
||||
"cls": JSONEncoder,
|
||||
"separators": (",", ": "),
|
||||
}
|
||||
|
||||
|
||||
def setup_app(config=None):
|
||||
app = Flask(__name__, static_folder=None)
|
||||
app.config.update(
|
||||
PROPAGATE_EXCEPTIONS=True
|
||||
PROPAGATE_EXCEPTIONS=True,
|
||||
RESTFUL_JSON=RESTFUL_JSON,
|
||||
)
|
||||
app.register_blueprint(v1.bp, url_prefix='/v1')
|
||||
return app
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import re
|
||||
import urllib.parse as urllib
|
||||
|
||||
|
@ -8,6 +9,7 @@ import decorator
|
|||
import flask
|
||||
import flask_restful as restful
|
||||
|
||||
from craton import api
|
||||
from craton.api.v1.validators import ensure_project_exists
|
||||
from craton.api.v1.validators import request_validate
|
||||
from craton.api.v1.validators import response_filter
|
||||
|
@ -22,10 +24,14 @@ class Resource(restful.Resource):
|
|||
response_filter]
|
||||
|
||||
def error_response(self, status_code, message):
|
||||
resp = flask.jsonify({
|
||||
'status': status_code,
|
||||
'message': message
|
||||
})
|
||||
body = json.dumps(
|
||||
{
|
||||
'status': status_code,
|
||||
'message': message
|
||||
},
|
||||
**api.RESTFUL_JSON,
|
||||
)
|
||||
resp = flask.make_response("{body}\n".format(body=body))
|
||||
resp.status_code = status_code
|
||||
return resp
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
# The code is auto generated, your change will be overwritten by
|
||||
# code generating.
|
||||
|
||||
from datetime import date
|
||||
from functools import wraps
|
||||
|
||||
from werkzeug.datastructures import MultiDict, Headers
|
||||
from flask import request, current_app, json
|
||||
from flask import request, current_app
|
||||
from flask_restful import abort
|
||||
from flask_restful.utils import unpack
|
||||
from jsonschema import Draft4Validator
|
||||
|
@ -143,14 +142,6 @@ def normalize(schema, data, required_defaults=None):
|
|||
return _normalize(schema, data), errors
|
||||
|
||||
|
||||
class JSONEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, o):
|
||||
if isinstance(o, date):
|
||||
return o.isoformat()
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
class FlaskValidatorAdaptor(object):
|
||||
|
||||
def __init__(self, schema):
|
||||
|
@ -282,13 +273,7 @@ def response_filter(view):
|
|||
if errors:
|
||||
abort(500, message='Expectation Failed', errors=errors)
|
||||
|
||||
return current_app.response_class(
|
||||
json.dumps(resp, cls=JSONEncoder) + '\n',
|
||||
status=status,
|
||||
headers=headers,
|
||||
mimetype='application/json'
|
||||
)
|
||||
|
||||
return resp, status, headers
|
||||
return wrapper
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import contextlib
|
||||
import docker
|
||||
import json
|
||||
import requests
|
||||
from retrying import retry
|
||||
from sqlalchemy import create_engine
|
||||
|
@ -220,28 +221,49 @@ class TestCase(testtools.TestCase):
|
|||
def assertBadRequest(self, response):
|
||||
self.assertEqual(requests.codes.BAD_REQUEST, response.status_code)
|
||||
|
||||
def assertJSON(self, response):
|
||||
if response.text:
|
||||
try:
|
||||
data = json.loads(response.text)
|
||||
except json.JSONDecodeError:
|
||||
self.fail("Response data is not JSON.")
|
||||
else:
|
||||
reference = "{formatted_data}\n".format(
|
||||
formatted_data=json.dumps(
|
||||
data, indent=2, sort_keys=True, separators=(',', ': ')
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
reference,
|
||||
response.text
|
||||
)
|
||||
|
||||
def get(self, url, headers=None, **params):
|
||||
resp = self.session.get(
|
||||
url, verify=False, headers=headers, params=params,
|
||||
)
|
||||
self.assertJSON(resp)
|
||||
return resp
|
||||
|
||||
def post(self, url, headers=None, data=None):
|
||||
resp = self.session.post(
|
||||
url, verify=False, headers=headers, json=data,
|
||||
)
|
||||
self.assertJSON(resp)
|
||||
return resp
|
||||
|
||||
def put(self, url, headers=None, data=None):
|
||||
resp = self.session.put(
|
||||
url, verify=False, headers=headers, json=data,
|
||||
)
|
||||
self.assertJSON(resp)
|
||||
return resp
|
||||
|
||||
def delete(self, url, headers=None, body=None):
|
||||
resp = self.session.delete(
|
||||
url, verify=False, headers=headers, json=body,
|
||||
)
|
||||
self.assertJSON(resp)
|
||||
return resp
|
||||
|
||||
def create_cloud(self, name, variables=None):
|
||||
|
|
Loading…
Reference in New Issue