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"]
예제 #2
0
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)
예제 #3
0
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
예제 #4
0
 def _swagger_file(**kwargs):
     app = web.Application()
     return SwaggerFile(
         app,
         spec_file="tests/testdata/petstore.yaml",
         **kwargs,
     )
예제 #5
0
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
예제 #6
0
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)
예제 #7
0
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")
예제 #8
0
 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"),
     )
예제 #9
0
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"
예제 #10
0
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"
    }
예제 #11
0
 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"),
     )