Answer API errors in the envelope, say when supplies are unread, badge each chain
Three more findings from the 2026-09-03 run.
Werkzeug answered 405, 415 and a malformed JSON body itself, in HTML. A client
written against the documented {status,data,meta} contract got a page of markup
with no error code, which is indistinguishable from the server having fallen
over. The 405 had a second edge: on a route the caller cannot otherwise see, a
method-not-allowed CONFIRMS the path exists, so a gated kiosk route meant to
read as absent announced itself by refusing the wrong verb. All three now
answer in the envelope, and only under /api/ - everything else is the SPA and
keeps the framework's behaviour, deep links included.
The Toner Report rendered "0 Printers Checked / 0 Low / 0 Critical" and "No
printers match the selected filter" while the API it had just called said
supply monitoring was unreachable. Zeros read as a clean bill of health for a
fleet nobody has looked at. The page now carries the reason the API gave and
suppresses the counts, because a number nobody measured is not a result. Same
defect shape as the supplies card fixed on 2026-08-29; `unavailable` was
already in the payload and the page ignored it.
Backup revisions badged "current" per (asset, kind). NTLARS settings describe a
MACHINE but are read off the controlling PC, so a machine with two reporting
PCs has two independent chains of the same kind - and only the higher revision
id was badged, so the second PC's newest revision showed as history and lost
its last-verified stamp. The machine looked like one source re-reporting rather
than two. sourcehostname is the chain; a revision without one forms its own,
which keeps the old behaviour for everything that has only ever had one source.
Nine tests. The envelope ones verified by planting: remove the three handlers
and three fail.
Scope: product
This commit is contained in:
@@ -435,6 +435,48 @@ def register_error_handlers(app: Flask):
|
||||
http_code=404
|
||||
)
|
||||
|
||||
# Werkzeug answers these three itself, in HTML, so a JSON client asking a
|
||||
# question slightly wrong got a page of markup with no error code and no
|
||||
# envelope - and on a route the caller cannot see, the 405 also confirmed
|
||||
# that the path exists, which is how a gated kiosk route meant to look
|
||||
# absent announced itself.
|
||||
#
|
||||
# Only under /api/. Everything else is the SPA, which needs the framework's
|
||||
# own behaviour (and its own catch-all) left alone.
|
||||
from flask import request as flask_request
|
||||
|
||||
def _api_request():
|
||||
return flask_request.path.startswith('/api/')
|
||||
|
||||
@app.errorhandler(405)
|
||||
def method_not_allowed_error(error):
|
||||
if not _api_request():
|
||||
return error
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'That method is not allowed on this endpoint.',
|
||||
http_code=405)
|
||||
|
||||
@app.errorhandler(415)
|
||||
def unsupported_media_type_error(error):
|
||||
if not _api_request():
|
||||
return error
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'This endpoint expects a JSON body; send '
|
||||
'Content-Type: application/json.',
|
||||
http_code=415)
|
||||
|
||||
@app.errorhandler(400)
|
||||
def bad_request_error(error):
|
||||
if not _api_request():
|
||||
return error
|
||||
# Werkzeug raises this for malformed JSON before any route sees it.
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'The request body could not be read as JSON.',
|
||||
http_code=400)
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_error(error):
|
||||
return error_response(
|
||||
|
||||
Reference in New Issue
Block a user