async def test_spec_file_validation_false(aiohttp_client, loop): app = web.Application(loop=loop) async def handler(request): assert "data" not in request assert request.rel_url.query["query"] == "str" return web.json_response() s = SwaggerFile(app, "/docs", "tests/testdata/petstore.yaml", validate=False) s.add_get("/pets", handler) client = await aiohttp_client(app) params = {"query": "str"} resp = await client.get("/pets", params=params) assert resp.status == 200 resp = await client.get("/docs/") assert resp.status == 200 resp = await client.get("/docs/swagger.json") assert resp.status == 200 spec = await resp.json() assert "/pets" in spec["paths"]
def main(): app = web.Application() s = SwaggerFile(app, "/docs", "petstore.yaml") s.add_routes([ web.get("/pets", get_all_pets), web.get("/pets/{pet_id}", get_one_pet), web.delete("/pets/{pet_id}", delete_one_pet), web.post("/pets", create_pet), ]) app["storage"] = {} web.run_app(app)
async def test_route_out_of_spec_file(aiohttp_client, loop): app = web.Application(loop=loop) s = SwaggerFile(app, "/docs", "tests/testdata/petstore.yaml") async def handler(request): return web.json_response() s.add_route("POST", "/r", handler) client = await aiohttp_client(app) resp = await client.post("/r", json={"array": "whatever"}) assert resp.status == 200
def _swagger_file(**kwargs): app = web.Application() return SwaggerFile( app, spec_file="tests/testdata/petstore.yaml", **kwargs, )
async def test_class_based_spec_file(aiohttp_client, loop): app = web.Application(loop=loop) s = SwaggerFile(app, "/docs", "tests/testdata/petstore.yaml") class Pets(web.View): async def get(self, limit: Optional[int] = None): pets = [] for i in range(limit or 3): pets.append({"id": i, "name": f"pet_{i}", "tag": f"tag_{i}"}) return web.json_response(pets) async def post(self, body: Dict): return web.json_response(body, status=201) s.add_routes([web.view("/pets", Pets)]) client = await aiohttp_client(app) resp = await client.get("/pets", params={"limit": 1}) assert resp.status == 200 assert await resp.json() == [{"id": 0, "name": "pet_0", "tag": "tag_0"}] resp = await client.get("/pets") assert resp.status == 200 assert await resp.json() == [ { "id": 0, "name": "pet_0", "tag": "tag_0" }, { "id": 1, "name": "pet_1", "tag": "tag_1" }, { "id": 2, "name": "pet_2", "tag": "tag_2" }, ] req = {"id": 10, "name": "pet", "tag": "tag"} resp = await client.post("/pets", json=req) assert resp.status == 201 assert await resp.json() == req
def main(): app = web.Application() s = SwaggerFile( app, spec_file="petstore.yaml", swagger_ui_settings=SwaggerUiSettings(path="/docs"), ) s.add_routes( [ web.get("/pets", get_all_pets), web.get("/pets/{pet_id}", get_one_pet), web.delete("/pets/{pet_id}", delete_one_pet), web.post("/pets", create_pet), ] ) app["storage"] = {} web.run_app(app)
async def test_deprecated_ui_path(): app = web.Application() with pytest.warns( FutureWarning, match="ui_path is deprecated and will be removed in 0.4.0, use swagger_ui_settings instead.", ): SwaggerDocs(app, "/docs") with pytest.warns( FutureWarning, match="ui_path is deprecated and will be removed in 0.4.0, use swagger_ui_settings instead.", ): SwaggerFile(app, "/docs", "tests/testdata/petstore.yaml")
def __init__( self, db: DbAccess, model_handler: ModelHandler, subscription_handler: SubscriptionHandler, workflow_handler: TaskHandlerService, message_bus: MessageBus, event_sender: AnalyticsEventSender, worker_task_queue: WorkerTaskQueue, cert_handler: CertificateHandler, config_handler: ConfigHandler, cli: CLI, query_parser: QueryParser, args: Namespace, ): self.db = db self.model_handler = model_handler self.subscription_handler = subscription_handler self.workflow_handler = workflow_handler self.message_bus = message_bus self.event_sender = event_sender self.worker_task_queue = worker_task_queue self.cert_handler = cert_handler self.config_handler = config_handler self.cli = cli self.query_parser = query_parser self.args = args self.app = web.Application( # note on order: the middleware is passed in the order provided. middlewares=[ metrics_handler, auth.auth_handler(args), cors_handler, error_handler(args, event_sender), default_middleware(self), ]) self.app.on_response_prepare.append(on_response_prepare) self.merge_max_wait_time = timedelta( seconds=args.merge_max_wait_time_seconds) self.session: Optional[ClientSession] = None self.in_shutdown = False self.websocket_handler: Dict[str, Tuple[Future, web.WebSocketResponse]] = { } # type: ignore # pypy static_path = os.path.abspath(os.path.dirname(__file__) + "/../static") ui_route = ([ web.get("/ui", self.forward("/ui/index.html")), web.get("/ui/", self.forward("/ui/index.html")), web.static("/ui/", self.args.ui_path), ] if self.args.ui_path else []) tsdb_route = [web.route(METH_ANY, "/tsdb/{tail:.+}", tsdb(self)) ] if self.args.tsdb_proxy_url else [] self.app.add_routes([ # Model operations web.get("/model", self.get_model), web.get("/model/uml", self.model_uml), web.patch("/model", self.update_model), # CRUD Graph operations web.get("/graph", self.list_graphs), web.get("/graph/{graph_id}", self.get_node), web.post("/graph/{graph_id}", self.create_graph), web.delete("/graph/{graph_id}", self.wipe), # No section of the graph # TODO: deprecated. Remove it. web.post("/graph/{graph_id}/query/raw", self.raw), web.post("/graph/{graph_id}/query/explain", self.explain), web.post("/graph/{graph_id}/query/list", self.query_list), web.post("/graph/{graph_id}/query/graph", self.query_graph_stream), web.post("/graph/{graph_id}/query/aggregate", self.query_aggregation), # search the graph web.post("/graph/{graph_id}/search/raw", self.raw), web.post("/graph/{graph_id}/search/explain", self.explain), web.post("/graph/{graph_id}/search/list", self.query_list), web.post("/graph/{graph_id}/search/graph", self.query_graph_stream), web.post("/graph/{graph_id}/search/aggregate", self.query_aggregation), # maintain the graph web.patch("/graph/{graph_id}/nodes", self.update_nodes), web.post("/graph/{graph_id}/merge", self.merge_graph), web.post("/graph/{graph_id}/batch/merge", self.update_merge_graph_batch), web.get("/graph/{graph_id}/batch", self.list_batches), web.post("/graph/{graph_id}/batch/{batch_id}", self.commit_batch), web.delete("/graph/{graph_id}/batch/{batch_id}", self.abort_batch), # node specific actions web.post("/graph/{graph_id}/node/{node_id}/under/{parent_node_id}", self.create_node), web.get("/graph/{graph_id}/node/{node_id}", self.get_node), web.patch("/graph/{graph_id}/node/{node_id}", self.update_node), web.delete("/graph/{graph_id}/node/{node_id}", self.delete_node), web.patch("/graph/{graph_id}/node/{node_id}/section/{section}", self.update_node), # Subscriptions web.get("/subscribers", self.list_all_subscriptions), web.get("/subscribers/for/{event_type}", self.list_subscription_for_event), # Subscription web.get("/subscriber/{subscriber_id}", self.get_subscriber), web.put("/subscriber/{subscriber_id}", self.update_subscriber), web.delete("/subscriber/{subscriber_id}", self.delete_subscriber), web.post("/subscriber/{subscriber_id}/{event_type}", self.add_subscription), web.delete("/subscriber/{subscriber_id}/{event_type}", self.delete_subscription), web.get("/subscriber/{subscriber_id}/handle", self.handle_subscribed), # CLI web.post("/cli/evaluate", self.evaluate), web.post("/cli/execute", self.execute), web.get("/cli/info", self.cli_info), # Event operations web.get("/events", self.handle_events), # Worker operations web.get("/work/queue", self.handle_work_tasks), web.get("/work/create", self.create_work), web.get("/work/list", self.list_work), # Serve static filed web.get("", self.redirect_to_api_doc), web.static("/static", static_path), # metrics web.get("/metrics", self.metrics), # config operations web.get("/configs", self.list_configs), web.put("/config/{config_id}", self.put_config), web.get("/config/{config_id}", self.get_config), web.patch("/config/{config_id}", self.patch_config), web.delete("/config/{config_id}", self.delete_config), # config model operations web.get("/configs/validation", self.list_config_models), web.get("/configs/model", self.get_configs_model), web.patch("/configs/model", self.update_configs_model), web.put("/config/{config_id}/validation", self.put_config_validation), web.get("/config/{config_id}/validation", self.get_config_validation), # ca operations web.get("/ca/cert", self.certificate), web.post("/ca/sign", self.sign_certificate), # system operations web.get("/system/ping", self.ping), web.get("/system/ready", self.ready), *ui_route, *tsdb_route, ]) SwaggerFile( self.app, spec_file=f"{static_path}/api-doc.yaml", swagger_ui_settings=SwaggerUiSettings(path="/api-doc", layout="BaseLayout", docExpansion="none"), )
async def test_swagger_file_no_spec(): app = web.Application() with pytest.raises(Exception) as exc_info: SwaggerFile(app) assert str( exc_info.value) == "spec file with swagger schema must be provided"
async def test_spec_file(aiohttp_client, loop): app = web.Application(loop=loop) s = SwaggerFile(app, "/docs", "tests/testdata/petstore.yaml") async def get_all_pets(request, limit: Optional[int] = None): pets = [] for i in range(limit or 3): pets.append({"id": i, "name": f"pet_{i}", "tag": f"tag_{i}"}) return web.json_response(pets) async def create_pet(request, body: Dict): return web.json_response(body, status=201) async def get_one_pet(request, pet_id: int): if pet_id in (1, 2, 3): return web.json_response({ "id": pet_id, "name": f"pet_{pet_id}", "tag": f"tag_{pet_id}" }) return web.json_response( { "code": 10, "message": f"pet with ID '{pet_id}' not found" }, status=500) s.add_routes([ web.get("/pets", get_all_pets), web.get("/pets/{pet_id}", get_one_pet), web.post("/pets", create_pet), ]) client = await aiohttp_client(app) resp = await client.get("/pets", params={"limit": 1}) assert resp.status == 200 assert await resp.json() == [{"id": 0, "name": "pet_0", "tag": "tag_0"}] resp = await client.get("/pets") assert resp.status == 200 assert await resp.json() == [ { "id": 0, "name": "pet_0", "tag": "tag_0" }, { "id": 1, "name": "pet_1", "tag": "tag_1" }, { "id": 2, "name": "pet_2", "tag": "tag_2" }, ] req = {"id": 10, "name": "pet", "tag": "tag"} resp = await client.post("/pets", json=req) assert resp.status == 201 assert await resp.json() == req resp = await client.get("/pets/1") assert resp.status == 200 assert await resp.json() == {"id": 1, "name": "pet_1", "tag": "tag_1"} resp = await client.get(f"/pets/1") assert resp.status == 200 assert await resp.json() == {"id": 1, "name": "pet_1", "tag": "tag_1"} resp = await client.get(f"/pets/100") assert resp.status == 500 assert await resp.json() == { "code": 10, "message": f"pet with ID '100' not found" }
def __add_routes(self, prefix: str) -> None: static_path = os.path.abspath(os.path.dirname(__file__) + "/../static") ui_route: List[AbstractRouteDef] = ( [web.static(f"{prefix}/ui/", self.config.api.ui_path)] if self.config.api.ui_path and Path(self.config.api.ui_path).exists() else [web.get(f"{prefix}/ui/index.html", self.no_ui)]) tsdb_route = ([ web.route(METH_ANY, prefix + "/tsdb/{tail:.+}", tsdb(self)) ] if self.config.api.tsdb_proxy_url else []) self.app.add_routes([ # Model operations web.get(prefix + "/model", self.get_model), web.get(prefix + "/model/uml", self.model_uml), web.patch(prefix + "/model", self.update_model), # CRUD Graph operations web.get(prefix + "/graph", self.list_graphs), web.get(prefix + "/graph/{graph_id}", self.get_node), web.post(prefix + "/graph/{graph_id}", self.create_graph), web.delete(prefix + "/graph/{graph_id}", self.wipe), # search the graph web.post(prefix + "/graph/{graph_id}/search/raw", self.raw), web.post(prefix + "/graph/{graph_id}/search/explain", self.explain), web.post(prefix + "/graph/{graph_id}/search/list", self.query_list), web.post(prefix + "/graph/{graph_id}/search/graph", self.query_graph_stream), web.post(prefix + "/graph/{graph_id}/search/aggregate", self.query_aggregation), # maintain the graph web.patch(prefix + "/graph/{graph_id}/nodes", self.update_nodes), web.post(prefix + "/graph/{graph_id}/merge", self.merge_graph), web.post(prefix + "/graph/{graph_id}/batch/merge", self.update_merge_graph_batch), web.get(prefix + "/graph/{graph_id}/batch", self.list_batches), web.post(prefix + "/graph/{graph_id}/batch/{batch_id}", self.commit_batch), web.delete(prefix + "/graph/{graph_id}/batch/{batch_id}", self.abort_batch), # node specific actions web.post( prefix + "/graph/{graph_id}/node/{node_id}/under/{parent_node_id}", self.create_node), web.get(prefix + "/graph/{graph_id}/node/{node_id}", self.get_node), web.patch(prefix + "/graph/{graph_id}/node/{node_id}", self.update_node), web.delete(prefix + "/graph/{graph_id}/node/{node_id}", self.delete_node), web.patch( prefix + "/graph/{graph_id}/node/{node_id}/section/{section}", self.update_node), # Subscriptions web.get(prefix + "/subscribers", self.list_all_subscriptions), web.get(prefix + "/subscribers/for/{event_type}", self.list_subscription_for_event), # Subscription web.get(prefix + "/subscriber/{subscriber_id}", self.get_subscriber), web.put(prefix + "/subscriber/{subscriber_id}", self.update_subscriber), web.delete(prefix + "/subscriber/{subscriber_id}", self.delete_subscriber), web.post(prefix + "/subscriber/{subscriber_id}/{event_type}", self.add_subscription), web.delete(prefix + "/subscriber/{subscriber_id}/{event_type}", self.delete_subscription), web.get(prefix + "/subscriber/{subscriber_id}/handle", self.handle_subscribed), # CLI web.post(prefix + "/cli/evaluate", self.evaluate), web.post(prefix + "/cli/execute", self.execute), web.get(prefix + "/cli/info", self.cli_info), # Event operations web.get(prefix + "/events", self.handle_events), # Worker operations web.get(prefix + "/work/queue", self.handle_work_tasks), web.get(prefix + "/work/create", self.create_work), web.get(prefix + "/work/list", self.list_work), # Serve static filed web.get(prefix, self.redirect_to_api_doc), web.static(prefix + "/static", static_path), # metrics web.get(prefix + "/metrics", self.metrics), # config operations web.get(prefix + "/configs", self.list_configs), web.put(prefix + "/config/{config_id}", self.put_config), web.get(prefix + "/config/{config_id}", self.get_config), web.patch(prefix + "/config/{config_id}", self.patch_config), web.delete(prefix + "/config/{config_id}", self.delete_config), # config model operations web.get(prefix + "/configs/validation", self.list_config_models), web.get(prefix + "/configs/model", self.get_configs_model), web.patch(prefix + "/configs/model", self.update_configs_model), web.put(prefix + "/config/{config_id}/validation", self.put_config_validation), web.get(prefix + "/config/{config_id}/validation", self.get_config_validation), # ca operations web.get(prefix + "/ca/cert", self.certificate), web.post(prefix + "/ca/sign", self.sign_certificate), # system operations web.get(prefix + "/system/ping", self.ping), web.get(prefix + "/system/ready", self.ready), # forwards web.get(prefix + "/tsdb", self.forward("/tsdb/")), web.get(prefix + "/ui", self.forward("/ui/index.html")), web.get(prefix + "/ui/", self.forward("/ui/index.html")), *ui_route, *tsdb_route, ]) SwaggerFile( self.app, spec_file=f"{static_path}/api-doc.yaml", swagger_ui_settings=SwaggerUiSettings(path=prefix + "/api-doc", layout="BaseLayout", docExpansion="none"), )