import json from os.path import join, dirname from jsonschema import validate from werkzeug.datastructures import FileStorage import flask_restx as restx from urllib.parse import parse_qs, urlparse with open(join(dirname(__file__), "postman-v1.schema.json")) as f: schema = json.load(f) class PostmanTest(object): def test_basic_export(self, app): api = restx.Api(app) data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 0 def test_export_infos(self, app): api = restx.Api( app, version="1.0", title="My API", description="This is a testing API", ) data = api.as_postman() validate(data, schema) assert data["name"] == "My API 1.0" assert data["description"] == "This is a testing API" def test_export_with_one_entry(self, app): api = restx.Api(app) @api.route("/test") class Test(restx.Resource): @api.doc("test_post") def post(self): """A test post""" pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["name"] == "test_post" assert request["description"] == "A test post" assert len(data["folders"]) == 1 folder = data["folders"][0] assert folder["name"] == "default" assert folder["description"] == "Default namespace" assert request["folder"] == folder["id"] def test_export_with_namespace(self, app): api = restx.Api(app) ns = api.namespace("test", "A test namespace") @ns.route("/test") class Test(restx.Resource): @api.doc("test_post") def post(self): """A test post""" pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["name"] == "test_post" assert request["description"] == "A test post" assert len(data["folders"]) == 1 folder = data["folders"][0] assert folder["name"] == "test" assert folder["description"] == "A test namespace" assert request["folder"] == folder["id"] def test_id_is_the_same(self, app): api = restx.Api(app) first = api.as_postman() second = api.as_postman() assert first["id"] == second["id"] def test_resources_order_in_folder(self, app): """It should preserve resources order""" api = restx.Api(app) ns = api.namespace("test", "A test namespace") @ns.route("/test1") class Test1(restx.Resource): @api.doc("test_post_z") def post(self): pass @ns.route("/test2") class Test2(restx.Resource): @api.doc("test_post_y") def post(self): pass @ns.route("/test3") class Test3(restx.Resource): @api.doc("test_post_x") def post(self): pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 3 assert len(data["folders"]) == 1 folder = data["folders"][0] assert folder["name"] == "test" expected_order = ("test_post_z", "test_post_y", "test_post_x") assert len(folder["order"]) == len(expected_order) for request_id, expected in zip(folder["order"], expected_order): request = list(filter(lambda r: r["id"] == request_id, data["requests"]))[0] assert request["name"] == expected def test_prefix_with_trailing_slash(self, app): api = restx.Api(app, prefix="/prefix/") @api.route("/test/") class Test(restx.Resource): @api.doc("test_post") def post(self): pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["url"] == "http://localhost/prefix/test/" def test_prefix_without_trailing_slash(self, app): api = restx.Api(app, prefix="/prefix") @api.route("/test/") class Test(restx.Resource): @api.doc("test_post") def post(self): pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["url"] == "http://localhost/prefix/test/" def test_path_variables(self, app): api = restx.Api(app) @api.route("/test////") class Test(restx.Resource): @api.doc("test_post") def post(self): pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["url"] == "http://localhost/test/:id/:integer/:number/" assert request["pathVariables"] == { "id": "", "integer": 0, "number": 0, } def test_url_variables_disabled(self, app): api = restx.Api(app) parser = api.parser() parser.add_argument("int", type=int) parser.add_argument("default", type=int, default=5) parser.add_argument("str", type=str) @api.route("/test/") class Test(restx.Resource): @api.expect(parser) def get(self): pass data = api.as_postman() validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["url"] == "http://localhost/test/" def test_url_variables_enabled(self, app): api = restx.Api(app) parser = api.parser() parser.add_argument("int", type=int) parser.add_argument("default", type=int, default=5) parser.add_argument("str", type=str) @api.route("/test/") class Test(restx.Resource): @api.expect(parser) def get(self): pass data = api.as_postman(urlvars=True) validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] qs = parse_qs(urlparse(request["url"]).query, keep_blank_values=True) assert "int" in qs assert qs["int"][0] == "0" assert "default" in qs assert qs["default"][0] == "5" assert "str" in qs assert qs["str"][0] == "" def test_headers(self, app): api = restx.Api(app) parser = api.parser() parser.add_argument("X-Header-1", location="headers", default="xxx") parser.add_argument("X-Header-2", location="headers", required=True) @api.route("/headers/") class TestHeaders(restx.Resource): @api.doc("headers") @api.expect(parser) def get(self): pass data = api.as_postman(urlvars=True) validate(data, schema) request = data["requests"][0] headers = dict(r.split(":") for r in request["headers"].splitlines()) assert headers["X-Header-1"] == "xxx" assert headers["X-Header-2"] == "" def test_content_type_header(self, app): api = restx.Api(app) form_parser = api.parser() form_parser.add_argument("param", type=int, help="Some param", location="form") file_parser = api.parser() file_parser.add_argument("in_files", type=FileStorage, location="files") @api.route("/json/") class TestJson(restx.Resource): @api.doc("json") def post(self): pass @api.route("/form/") class TestForm(restx.Resource): @api.doc("form") @api.expect(form_parser) def post(self): pass @api.route("/file/") class TestFile(restx.Resource): @api.doc("file") @api.expect(file_parser) def post(self): pass @api.route("/get/") class TestGet(restx.Resource): @api.doc("get") def get(self): pass data = api.as_postman(urlvars=True) validate(data, schema) requests = dict((r["name"], r["headers"]) for r in data["requests"]) assert requests["json"] == "Content-Type:application/json" assert requests["form"] == "Content-Type:multipart/form-data" assert requests["file"] == "Content-Type:multipart/form-data" # No content-type on get assert requests["get"] == "" def test_method_security_headers(self, app): api = restx.Api( app, authorizations={ "apikey": {"type": "apiKey", "in": "header", "name": "X-API"} }, ) @api.route("/secure/") class Secure(restx.Resource): @api.doc("secure", security="apikey") def get(self): pass @api.route("/unsecure/") class Unsecure(restx.Resource): @api.doc("unsecure") def get(self): pass data = api.as_postman() validate(data, schema) requests = dict((r["name"], r["headers"]) for r in data["requests"]) assert requests["unsecure"] == "" assert requests["secure"] == "X-API:" def test_global_security_headers(self, app): api = restx.Api( app, security="apikey", authorizations={ "apikey": {"type": "apiKey", "in": "header", "name": "X-API"} }, ) @api.route("/test/") class Test(restx.Resource): def get(self): pass data = api.as_postman() validate(data, schema) request = data["requests"][0] headers = dict(r.split(":") for r in request["headers"].splitlines()) assert headers["X-API"] == "" def test_oauth_security_headers(self, app): api = restx.Api( app, security="oauth", authorizations={ "oauth": { "type": "oauth2", "authorizationUrl": "https://somewhere.com/oauth/authorize", "flow": "implicit", "scopes": {"read": "Can read", "write": "Can write"}, } }, ) @api.route("/test/") class Test(restx.Resource): def get(self): pass data = api.as_postman() validate(data, schema) # request = data['requests'][0] # headers = dict(r.split(':') for r in request['headers'].splitlines()) # # assert headers['X-API'] == '' def test_export_with_swagger(self, app): api = restx.Api(app) data = api.as_postman(swagger=True) validate(data, schema) assert len(data["requests"]) == 1 request = data["requests"][0] assert request["name"] == "Swagger specifications" assert request["description"] == "The API Swagger specifications as JSON" assert request["url"] == "http://localhost/swagger.json"