From 8ed910b29a8d49dfc1bdafdf87da7c9c78ae78d3 Mon Sep 17 00:00:00 2001 From: Lars Karlitski Date: Thu, 30 May 2019 02:12:03 +0200 Subject: [PATCH] composer: Set up a custom HTTP error handler Override flask's default error handler, because that return html. Return JSON instead with the usual { "status": false, "errors": [ ... ] } pattern. --- src/pylorax/api/errors.py | 3 +++ src/pylorax/api/server.py | 6 ++++++ tests/pylorax/test_server.py | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/pylorax/api/errors.py b/src/pylorax/api/errors.py index cff356ae..c4d1bd95 100644 --- a/src/pylorax/api/errors.py +++ b/src/pylorax/api/errors.py @@ -16,6 +16,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# HTTP errors +HTTP_ERROR = "HTTPError" + # Returned from the API when either an invalid compose type is given, or not # compose type is given. BAD_COMPOSE_TYPE = "BadComposeType" diff --git a/src/pylorax/api/server.py b/src/pylorax/api/server.py index a4265273..c3bbf257 100644 --- a/src/pylorax/api/server.py +++ b/src/pylorax/api/server.py @@ -21,9 +21,11 @@ from collections import namedtuple from flask import Flask, jsonify, redirect, send_from_directory from glob import glob import os +import werkzeug from pylorax import vernum from pylorax.api.crossdomain import crossdomain +from pylorax.api.errors import HTTP_ERROR from pylorax.api.v0 import v0_api from pylorax.sysutils import joinpaths @@ -79,4 +81,8 @@ def v0_status(): db_supported=True, msgs=server.config["TEMPLATE_ERRORS"]) +@server.errorhandler(werkzeug.exceptions.HTTPException) +def bad_request(error): + return jsonify(status=False, errors=[{ "id": HTTP_ERROR, "code": error.code, "msg": error.name }]), error.code + v0_api(server) diff --git a/tests/pylorax/test_server.py b/tests/pylorax/test_server.py index 9ed66cad..d4c5c3a2 100644 --- a/tests/pylorax/test_server.py +++ b/tests/pylorax/test_server.py @@ -1553,6 +1553,26 @@ class ServerTestCase(unittest.TestCase): self.assertTrue(len(data["errors"]) > 0) self.assertEqual(data["errors"][0]["id"], "UnknownBlueprint") + def test_404(self): + """Test that a 404 returns JSON""" + resp = self.server.get("/marmalade") + print(resp) + print(resp.data) + self.assertEqual(resp.status_code, 404) + self.assertEqual(json.loads(resp.data), { + "status": False, + "errors": [{ "id": "HTTPError", "code": 404, "msg": "Not Found" }] + }) + + def test_405(self): + """Test that a 405 returns JSON""" + resp = self.server.post("/api/status") + self.assertEqual(resp.status_code, 405) + self.assertEqual(json.loads(resp.data), { + "status": False, + "errors": [{ "id": "HTTPError", "code": 405, "msg": "Method Not Allowed" }] + }) + @contextmanager def in_tempdir(prefix='tmp'): """Execute a block of code with chdir in a temporary location"""