From 862f5a3a535556dbbc8c73a59f0335f85b2be984 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 1 Jun 2015 14:20:24 +0100 Subject: [PATCH] Add structure for adding examples to HTTP APIs. Use 'x-example' to add examples to parameters which are not in 'body' (swagger doesn't define that currently). Add profile API examples. Add necessary glue and templates to make it all work. --- api/client-server/v1/profile.yaml | 12 +++++ api/validator.js | 2 + .../matrix_templates/templates/http-api.tmpl | 13 +++-- templating/matrix_templates/units.py | 48 +++++++++++++++++-- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/api/client-server/v1/profile.yaml b/api/client-server/v1/profile.yaml index b3b5f05d..a6d16d41 100644 --- a/api/client-server/v1/profile.yaml +++ b/api/client-server/v1/profile.yaml @@ -29,12 +29,17 @@ paths: name: userId description: The user whose display name to set. required: true + x-example: "@alice:example.com" - in: body name: displayName description: The display name info. required: true schema: type: object + example: |- + { + "displayname": "Alice Margatroid" + } properties: displayname: type: string @@ -59,6 +64,7 @@ paths: name: userId description: The user whose display name to get. required: true + x-example: "@alice:example.com" responses: 200: description: The display name for this user. @@ -86,12 +92,17 @@ paths: name: userId description: The user whose avatar URL to set. required: true + x-example: "@alice:example.com" - in: body name: avatar_url description: The avatar url info. required: true schema: type: object + example: |- + { + "avatar_url": "mxc:/matrix.org/wefh34uihSDRGhw34" + } properties: avatar_url: type: string @@ -116,6 +127,7 @@ paths: name: userId description: The user whose avatar URL to get. required: true + x-example: "@alice:example.com" responses: 200: description: The avatar URL for this user. diff --git a/api/validator.js b/api/validator.js index 988788a2..b824b649 100644 --- a/api/validator.js +++ b/api/validator.js @@ -27,8 +27,10 @@ if (!opts.schema) { parser.parse(opts.schema, function(err, api, metadata) { if (!err) { console.log("%s is valid.", opts.schema); + process.exit(0); return; } console.log(metadata); console.error(err); + process.exit(1); }); \ No newline at end of file diff --git a/templating/matrix_templates/templates/http-api.tmpl b/templating/matrix_templates/templates/http-api.tmpl index 2bfb2e27..858ae534 100644 --- a/templating/matrix_templates/templates/http-api.tmpl +++ b/templating/matrix_templates/templates/http-api.tmpl @@ -2,10 +2,8 @@ {{(5 + (endpoint.path | length) + (endpoint.method | length)) * title_kind}} {{endpoint.desc | wrap(80)}} - -{{":Rate-limited: Yes." if endpoint.rate_limited else ""}} -{{":Requires auth: Yes." if endpoint.requires_auth else ""}} - +{{":Rate-limited: Yes." if endpoint.rate_limited else "" }} +{{":Requires auth: Yes." if endpoint.requires_auth else "" }} Request format: ================== ================= =========== =============================== @@ -17,3 +15,10 @@ param.loc|length)}}{{param.desc|indent(12-param.type|length)|wrap(31)|indent_blo {% endfor %} ================== ================= =========== =============================== +Example request:: + + {{endpoint.example.req | indent_block(2)}} + +Example response:: + + {{endpoint.example.res | indent_block(2)}} \ No newline at end of file diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index d7f5a780..65c67d13 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -4,6 +4,7 @@ import inspect import json import os import subprocess +import urllib import yaml def get_json_schema_object_fields(obj, enforce_title=False): @@ -113,7 +114,11 @@ class MatrixUnits(Units): "req_params": [], "responses": [ # { code: 200, [ {row_info} ]} - ] + ], + "example": { + "req": "", + "res": "" + } } self.log(".o.O.o. Endpoint: %s %s" % (method, path)) for param in single_api.get("parameters", []): @@ -184,11 +189,44 @@ class MatrixUnits(Units): "code": 200, "http": "200 OK", "desc": res200["description"], - "params": res200params, - "example": res200.get("examples", {}).get( - "application/json", "" - ) + "params": res200params } + # add example response if it has one + endpoint["example"]["res"] = res200.get("examples", {}).get( + "application/json", "" + ) + # form example request if it has one. It "has one" if all params + # have either "x-example" or a "schema" with an "example". + params_missing_examples = [ + p for p in single_api.get("parameters", []) if ( + "x-example" not in p and + not Units.prop(p, "schema/example") + ) + ] + if len(params_missing_examples) == 0: + path_template = api.get("basePath", "") + path + qps = {} + body = "" + for param in single_api.get("parameters", []): + if param["in"] == "path": + path_template = path_template.replace( + "{%s}" % param["name"], urllib.quote( + param["x-example"] + ) + ) + elif param["in"] == "body": + body = param["schema"]["example"] + elif param["in"] == "query": + qps[param["name"]] = qps[param["x-example"]] + query_string = "" if len(qps) == 0 else "?"+urllib.urlencode(qps) + endpoint["example"]["req"] = "%s %s%s\n%s" % ( + method.upper(), path_template, query_string, body + ) + else: + self.log( + "The following parameters are missing examples :( \n %s" % + [ p["name"] for p in params_missing_examples ] + ) endpoint["responses"].append(ok_res) endpoints.append(endpoint)