From cb07902cb6b3bcdbf31da00847bed32cd8b9a629 Mon Sep 17 00:00:00 2001 From: Alexandre Terrasa Date: Thu, 25 Aug 2016 00:44:43 -0400 Subject: [PATCH] nitweb: better error responses from API Signed-off-by: Alexandre Terrasa --- src/web/api_feedback.nit | 15 ++++----------- src/web/api_graph.nit | 7 ++----- src/web/api_metrics.nit | 7 ++----- src/web/api_model.nit | 20 ++++++++------------ src/web/web_base.nit | 40 ++++++++++++++++++++++++++++++++++++++-- 5 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/web/api_feedback.nit b/src/web/api_feedback.nit index 221a25e..e2bfa9a 100644 --- a/src/web/api_feedback.nit +++ b/src/web/api_feedback.nit @@ -36,28 +36,21 @@ class APIStars redef fun get(req, res) do var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end - + if mentity == null then return res.json mentity_ratings(mentity) end redef fun post(req, res) do var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end + if mentity == null then return var obj = req.body.parse_json if not obj isa JsonObject then - res.error 400 + res.api_error(400, "Expected a JSON object") return end var rating = obj["rating"] if not rating isa Int then - res.error 400 + res.api_error(400, "Expected a key `rating`") return end diff --git a/src/web/api_graph.nit b/src/web/api_graph.nit index 851da48..cf6e105 100644 --- a/src/web/api_graph.nit +++ b/src/web/api_graph.nit @@ -31,13 +31,10 @@ class APIInheritanceGraph super APIHandler redef fun get(req, res) do + var mentity = mentity_from_uri(req, res) + if mentity == null then return var pdepth = req.int_arg("pdepth") var cdepth = req.int_arg("cdepth") - var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end var g = new InheritanceGraph(mentity, view) res.send g.draw(pdepth, cdepth).to_svg end diff --git a/src/web/api_metrics.nit b/src/web/api_metrics.nit index af95f53..1683cbb 100644 --- a/src/web/api_metrics.nit +++ b/src/web/api_metrics.nit @@ -69,13 +69,10 @@ class APIStructuralMetrics redef fun get(req, res) do var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end + if mentity == null then return var metrics = mentity.collect_metrics(self) if metrics == null then - res.error 404 + res.api_error(404, "No metric for mentity `{mentity.full_name}`") return end res.json metrics diff --git a/src/web/api_model.nit b/src/web/api_model.nit index 2b39462..4c9fb8e 100644 --- a/src/web/api_model.nit +++ b/src/web/api_model.nit @@ -143,10 +143,7 @@ class APIEntityInheritance redef fun get(req, res) do var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end + if mentity == null then return res.json mentity.hierarchy_poset(view)[mentity] end end @@ -159,13 +156,10 @@ class APIEntityLinearization redef fun get(req, res) do var mentity = mentity_from_uri(req, res) - if mentity == null then - res.error 404 - return - end + if mentity == null then return var lin = mentity.collect_linearization(config.mainmodule) if lin == null then - res.error 404 + res.api_error(404, "No linearization for mentity `{mentity.full_name}`") return end res.json new JsonArray.from(lin) @@ -180,6 +174,7 @@ class APIEntityDefs redef fun get(req, res) do var mentity = mentity_from_uri(req, res) + if mentity == null then return var arr = new JsonArray if mentity isa MModule then for mclassdef in mentity.mclassdefs do arr.add mclassdef @@ -190,7 +185,7 @@ class APIEntityDefs else if mentity isa MProperty then for mpropdef in mentity.mpropdefs do arr.add mpropdef else - res.error 404 + res.api_error(404, "No definition list for mentity `{mentity.full_name}`") return end res.json arr @@ -218,6 +213,7 @@ class APIEntityUML redef fun get(req, res) do var mentity = mentity_from_uri(req, res) + if mentity == null then return var dot if mentity isa MClassDef then mentity = mentity.mclass if mentity isa MClass then @@ -227,7 +223,7 @@ class APIEntityUML var uml = new UMLModel(view, mentity) dot = uml.generate_package_uml.write_to_string else - res.error 404 + res.api_error(404, "No UML for mentity `{mentity.full_name}`") return end res.send render_dot(dot) @@ -245,7 +241,7 @@ class APIEntityCode if mentity == null then return var source = render_source(mentity) if source == null then - res.error 404 + res.api_error(404, "No code for mentity `{mentity.full_name}`") return end res.send source diff --git a/src/web/web_base.nit b/src/web/web_base.nit index 94bfd70..043bd6c 100644 --- a/src/web/web_base.nit +++ b/src/web/web_base.nit @@ -72,12 +72,12 @@ abstract class APIHandler fun mentity_from_uri(req: HttpRequest, res: HttpResponse): nullable MEntity do var id = req.param("id") if id == null then - res.error 400 + res.api_error(400, "Expected mentity full name") return null end var mentity = find_mentity(view, id) if mentity == null then - res.error 404 + res.api_error(404, "MEntity `{id}` not found") end return mentity end @@ -91,6 +91,42 @@ class APIRouter var config: NitwebConfig end +redef class HttpResponse + + # Return an HTTP error response with `status` + # + # Like the rest of the API, errors are formated as JSON: + # ~~~json + # { "status": 404, "message": "Not found" } + # ~~~ + fun api_error(status: Int, message: String) do + json(new APIError(status, message), status) + end +end + +# An error returned by the API. +# +# Can be serialized to json. +class APIError + super Jsonable + + # Reponse status + var status: Int + + # Response error message + var message: String + + # Json Object for this error + var json: JsonObject is lazy do + var obj = new JsonObject + obj["status"] = status + obj["message"] = message + return obj + end + + redef fun to_json do return json.to_json +end + redef class MEntity # URL to `self` within the web interface. -- 1.7.9.5