diff --git a/src/actions/action_default_v1.h b/src/actions/action_default_v1.h index d54ecd95..6331d49f 100644 --- a/src/actions/action_default_v1.h +++ b/src/actions/action_default_v1.h @@ -16,10 +16,21 @@ class ActionDefault_v1 : public sourcemeta::one::Action { public: - ActionDefault_v1(const std::filesystem::path &base, - const sourcemeta::core::URITemplateRouterView &router, - const sourcemeta::core::URITemplateRouter::Identifier) - : sourcemeta::one::Action{base, router.base_path()} {} + ActionDefault_v1( + const std::filesystem::path &base, + const sourcemeta::core::URITemplateRouterView &router, + const sourcemeta::core::URITemplateRouter::Identifier identifier) + : sourcemeta::one::Action{base, router.base_path()} { + // TODO: This implies the API is mounted + this->error_schema_ = + std::string{this->base_path()} + "/self/v1/schemas/api/error"; + + router.arguments(identifier, [this](const auto &key, const auto &value) { + if (key == "errorSchema") { + this->error_schema_ = std::get(value); + } + }); + } auto run(const std::span, sourcemeta::one::HTTPRequest &request, @@ -31,8 +42,7 @@ class ActionDefault_v1 : public sourcemeta::one::Action { path[this->base_path().size()] != '/')) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", this->error_schema_); return; } @@ -48,19 +58,18 @@ class ActionDefault_v1 : public sourcemeta::one::Action { ActionServeMetapackFile_v1::serve( this->base() / "explorer" / "%" / "directory-html.metapack", sourcemeta::one::STATUS_OK, false, {}, {}, request, response, - this->base_path()); + this->error_schema_); return; } else if (request.method() == "get" || request.method() == "head") { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", this->error_schema_); return; } else { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "method-not-allowed", "This HTTP method is invalid for this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } } @@ -68,7 +77,7 @@ class ActionDefault_v1 : public sourcemeta::one::Action { if (path.ends_with(".json")) { ActionJSONSchemaServe_v1::serve(this->base(), path.substr(0, path.size() - 5), request, - response, this->base_path()); + response, this->error_schema_); return; } @@ -80,31 +89,34 @@ class ActionDefault_v1 : public sourcemeta::one::Action { ActionServeMetapackFile_v1::serve( explorer_path / "schema-html.metapack", sourcemeta::one::STATUS_OK, false, {}, {}, request, response, - this->base_path()); + this->error_schema_); } else { explorer_path /= "directory-html.metapack"; if (std::filesystem::exists(explorer_path)) { ActionServeMetapackFile_v1::serve( explorer_path, sourcemeta::one::STATUS_OK, false, {}, {}, - request, response, this->base_path()); + request, response, this->error_schema_); } else { ActionServeMetapackFile_v1::serve( this->base() / "explorer" / "%" / "404.metapack", sourcemeta::one::STATUS_NOT_FOUND, false, {}, {}, request, - response, this->base_path()); + response, this->error_schema_); } } } else { ActionJSONSchemaServe_v1::serve(this->base(), path, request, response, - this->base_path()); + this->error_schema_); } } else { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", this->error_schema_); } } + +private: + // TODO: This should be a string view + std::string error_schema_; }; #endif diff --git a/src/actions/action_health_check_v1.h b/src/actions/action_health_check_v1.h index d29c6564..64ced5c4 100644 --- a/src/actions/action_health_check_v1.h +++ b/src/actions/action_health_check_v1.h @@ -13,10 +13,17 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action { public: - ActionHealthCheck_v1(const std::filesystem::path &base, - const sourcemeta::core::URITemplateRouterView &router, - const sourcemeta::core::URITemplateRouter::Identifier) - : sourcemeta::one::Action{base, router.base_path()} {} + ActionHealthCheck_v1( + const std::filesystem::path &base, + const sourcemeta::core::URITemplateRouterView &router, + const sourcemeta::core::URITemplateRouter::Identifier identifier) + : sourcemeta::one::Action{base, router.base_path()} { + router.arguments(identifier, [this](const auto &key, const auto &value) { + if (key == "errorSchema") { + this->error_schema_ = std::get(value); + } + }); + } auto run(const std::span, sourcemeta::one::HTTPRequest &request, @@ -25,7 +32,7 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "method-not-allowed", "This HTTP method is invalid for this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -34,6 +41,9 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action { sourcemeta::one::send_response(sourcemeta::one::STATUS_OK, request, response); } + +private: + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_jsonschema_evaluate_v1.h b/src/actions/action_jsonschema_evaluate_v1.h index 3a4cb19b..a07d7cf6 100644 --- a/src/actions/action_jsonschema_evaluate_v1.h +++ b/src/actions/action_jsonschema_evaluate_v1.h @@ -34,6 +34,10 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { router.arguments(identifier, [this](const auto &key, const auto &value) { if (key == "mode") { this->mode_ = static_cast(std::get(value)); + } else if (key == "responseSchema") { + this->response_schema_ = std::get(value); + } else if (key == "errorSchema") { + this->error_schema_ = std::get(value); } }); } @@ -64,12 +68,11 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "no-template", "This schema was not precompiled for schema evaluation", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); } else { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", this->error_schema_); } return; @@ -92,16 +95,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( callback_request, callback_response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR, - "uncaught-error", exception.what(), - std::string{this->base_path()} + - "/self/v1/schemas/api/error"); + "uncaught-error", exception.what(), this->error_schema_); } }); } else { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "method-not-allowed", "This HTTP method is invalid for this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); } } @@ -314,15 +315,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_PAYLOAD_TOO_LARGE, "payload-too-large", "The request body is too large", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } if (body.empty()) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_BAD_REQUEST, "no-instance", - "You must pass an instance to validate against", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "You must pass an instance to validate against", this->error_schema_); return; } @@ -331,15 +331,7 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { response.write_status(sourcemeta::one::STATUS_OK); response.write_header("Content-Type", "application/json"); response.write_header("Access-Control-Allow-Origin", "*"); - if (mode == EvaluateMode::Trace) { - sourcemeta::one::write_link_header( - response, std::string{this->base_path()} + - "/self/v1/schemas/api/schemas/trace/response"); - } else { - sourcemeta::one::write_link_header( - response, std::string{this->base_path()} + - "/self/v1/schemas/api/schemas/evaluate/response"); - } + sourcemeta::one::write_link_header(response, this->response_schema_); std::ostringstream payload; sourcemeta::core::prettify(result, payload); @@ -349,12 +341,13 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action { } catch (const std::exception &exception) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR, - "evaluation-error", exception.what(), - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "evaluation-error", exception.what(), this->error_schema_); } } EvaluateMode mode_{EvaluateMode::Standard}; + std::string_view response_schema_; + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_jsonschema_serve_v1.h b/src/actions/action_jsonschema_serve_v1.h index f59762e1..1eae3b2c 100644 --- a/src/actions/action_jsonschema_serve_v1.h +++ b/src/actions/action_jsonschema_serve_v1.h @@ -21,14 +21,20 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action { ActionJSONSchemaServe_v1( const std::filesystem::path &base, const sourcemeta::core::URITemplateRouterView &router, - const sourcemeta::core::URITemplateRouter::Identifier) - : sourcemeta::one::Action{base, router.base_path()} {} + const sourcemeta::core::URITemplateRouter::Identifier identifier) + : sourcemeta::one::Action{base, router.base_path()} { + router.arguments(identifier, [this](const auto &key, const auto &value) { + if (key == "errorSchema") { + this->error_schema_ = std::get(value); + } + }); + } static auto serve(const std::filesystem::path &base, std::string_view schema_path, sourcemeta::one::HTTPRequest &request, sourcemeta::one::HTTPResponse &response, - std::string_view base_path = {}) -> void { + std::string_view error_schema) -> void { // Otherwise we may get unexpected results in case-sensitive file-systems std::string lowercase_path{schema_path}; std::ranges::transform( @@ -56,8 +62,7 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action { !std::filesystem::exists(absolute_path)) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", error_schema); return; } @@ -65,19 +70,23 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action { // For HTTP imports, as Deno won't like the `application/schema+json` one ActionServeMetapackFile_v1::serve( absolute_path, sourcemeta::one::STATUS_OK, true, "application/json", - {}, request, response, base_path); + {}, request, response, error_schema); } else { ActionServeMetapackFile_v1::serve(absolute_path, sourcemeta::one::STATUS_OK, true, {}, - {}, request, response, base_path); + {}, request, response, error_schema); } } auto run(const std::span matches, sourcemeta::one::HTTPRequest &request, sourcemeta::one::HTTPResponse &response) -> void override { - serve(this->base(), matches.front(), request, response, this->base_path()); + serve(this->base(), matches.front(), request, response, + this->error_schema_); } + +private: + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_not_found_v1.h b/src/actions/action_not_found_v1.h index c2156e17..81297561 100644 --- a/src/actions/action_not_found_v1.h +++ b/src/actions/action_not_found_v1.h @@ -13,19 +13,28 @@ class ActionNotFound_v1 : public sourcemeta::one::Action { public: - ActionNotFound_v1(const std::filesystem::path &base, - const sourcemeta::core::URITemplateRouterView &router, - const sourcemeta::core::URITemplateRouter::Identifier) - : sourcemeta::one::Action{base, router.base_path()} {} + ActionNotFound_v1( + const std::filesystem::path &base, + const sourcemeta::core::URITemplateRouterView &router, + const sourcemeta::core::URITemplateRouter::Identifier identifier) + : sourcemeta::one::Action{base, router.base_path()} { + router.arguments(identifier, [this](const auto &key, const auto &value) { + if (key == "errorSchema") { + this->error_schema_ = std::get(value); + } + }); + } auto run(const std::span, sourcemeta::one::HTTPRequest &request, sourcemeta::one::HTTPResponse &response) -> void override { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", this->error_schema_); } + +private: + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_schema_search_v1.h b/src/actions/action_schema_search_v1.h index 6a47e18f..896e93c5 100644 --- a/src/actions/action_schema_search_v1.h +++ b/src/actions/action_schema_search_v1.h @@ -19,11 +19,20 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { public: - ActionSchemaSearch_v1(const std::filesystem::path &base, - const sourcemeta::core::URITemplateRouterView &router, - const sourcemeta::core::URITemplateRouter::Identifier) + ActionSchemaSearch_v1( + const std::filesystem::path &base, + const sourcemeta::core::URITemplateRouterView &router, + const sourcemeta::core::URITemplateRouter::Identifier identifier) : sourcemeta::one::Action{base, router.base_path()}, - search_view_{base / "explorer" / "%" / "search.metapack"} {} + search_view_{base / "explorer" / "%" / "search.metapack"} { + router.arguments(identifier, [this](const auto &key, const auto &value) { + if (key == "responseSchema") { + this->response_schema_ = std::get(value); + } else if (key == "errorSchema") { + this->error_schema_ = std::get(value); + } + }); + } auto run(const std::span, sourcemeta::one::HTTPRequest &request, @@ -33,7 +42,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "method-not-allowed", "This HTTP method is invalid for this URL", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -42,7 +51,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_BAD_REQUEST, "missing-query", "You must provide a query parameter to search for", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -52,7 +61,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { request, response, sourcemeta::one::STATUS_BAD_REQUEST, "invalid-search-query", "The search query must not exceed 256 characters", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -72,7 +81,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { request, response, sourcemeta::one::STATUS_BAD_REQUEST, "invalid-search-limit", "The limit must be a positive integer between 1 and 100", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -105,7 +114,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { "invalid-search-scope", "The scope must be a comma-separated list of: path, title, " "description", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -122,7 +131,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { "invalid-search-scope", "The scope must be a comma-separated list of: path, title, " "description", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } } @@ -131,9 +140,7 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { response.write_status(sourcemeta::one::STATUS_OK); response.write_header("Access-Control-Allow-Origin", "*"); response.write_header("Content-Type", "application/json"); - sourcemeta::one::write_link_header( - response, std::string{this->base_path()} + - "/self/v1/schemas/api/schemas/search/response"); + sourcemeta::one::write_link_header(response, this->response_schema_); std::ostringstream output; sourcemeta::core::prettify(result, output); sourcemeta::one::send_response(sourcemeta::one::STATUS_OK, request, @@ -143,6 +150,8 @@ class ActionSchemaSearch_v1 : public sourcemeta::one::Action { private: sourcemeta::one::SearchView search_view_; + std::string_view response_schema_; + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_serve_explorer_artifact_v1.h b/src/actions/action_serve_explorer_artifact_v1.h index 868d99f6..08e11b08 100644 --- a/src/actions/action_serve_explorer_artifact_v1.h +++ b/src/actions/action_serve_explorer_artifact_v1.h @@ -25,6 +25,8 @@ class ActionServeExplorerArtifact_v1 : public sourcemeta::one::Action { this->artifact_ = std::get(value); } else if (key == "responseSchema") { this->response_schema_ = std::get(value); + } else if (key == "errorSchema") { + this->error_schema_ = std::get(value); } }); } @@ -40,12 +42,13 @@ class ActionServeExplorerArtifact_v1 : public sourcemeta::one::Action { absolute_path /= std::string{this->artifact_} + ".metapack"; ActionServeMetapackFile_v1::serve(absolute_path, sourcemeta::one::STATUS_OK, true, {}, this->response_schema_, request, - response, this->base_path()); + response, this->error_schema_); } private: std::string_view artifact_; std::string_view response_schema_; + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_serve_metapack_file_v1.h b/src/actions/action_serve_metapack_file_v1.h index 3a526de6..a2ce0717 100644 --- a/src/actions/action_serve_metapack_file_v1.h +++ b/src/actions/action_serve_metapack_file_v1.h @@ -28,20 +28,19 @@ class ActionServeMetapackFile_v1 { std::string_view link, sourcemeta::one::HTTPRequest &request, sourcemeta::one::HTTPResponse &response, - std::string_view base_path = {}) -> void { + std::string_view error_schema) -> void { if (request.method() != "get" && request.method() != "head") { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED, "method-not-allowed", "This HTTP method is invalid for this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + error_schema); return; } if (!std::filesystem::exists(absolute_path)) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", error_schema); return; } @@ -50,8 +49,7 @@ class ActionServeMetapackFile_v1 { sizeof(sourcemeta::one::MetapackHeader) + sizeof(std::uint32_t)) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", error_schema); return; } @@ -59,8 +57,7 @@ class ActionServeMetapackFile_v1 { if (!info.has_value()) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", error_schema); return; } @@ -152,8 +149,7 @@ class ActionServeMetapackFile_v1 { if (!payload_start.has_value()) { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found", - "There is nothing at this URL", - std::string{base_path} + "/self/v1/schemas/api/error"); + "There is nothing at this URL", error_schema); return; } diff --git a/src/actions/action_serve_schema_artifact_v1.h b/src/actions/action_serve_schema_artifact_v1.h index 71bb40ad..36bc1949 100644 --- a/src/actions/action_serve_schema_artifact_v1.h +++ b/src/actions/action_serve_schema_artifact_v1.h @@ -25,6 +25,8 @@ class ActionServeSchemaArtifact_v1 : public sourcemeta::one::Action { this->artifact_ = std::get(value); } else if (key == "responseSchema") { this->response_schema_ = std::get(value); + } else if (key == "errorSchema") { + this->error_schema_ = std::get(value); } }); } @@ -36,7 +38,7 @@ class ActionServeSchemaArtifact_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR, "missing-schema-match", "This action requires a schema path match", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } @@ -44,12 +46,13 @@ class ActionServeSchemaArtifact_v1 : public sourcemeta::one::Action { absolute_path /= std::string{this->artifact_} + ".metapack"; ActionServeMetapackFile_v1::serve(absolute_path, sourcemeta::one::STATUS_OK, true, {}, this->response_schema_, request, - response, this->base_path()); + response, this->error_schema_); } private: std::string_view artifact_; std::string_view response_schema_; + std::string_view error_schema_; }; #endif diff --git a/src/actions/action_serve_static_v1.h b/src/actions/action_serve_static_v1.h index 64261079..e1758617 100644 --- a/src/actions/action_serve_static_v1.h +++ b/src/actions/action_serve_static_v1.h @@ -23,6 +23,8 @@ class ActionServeStatic_v1 : public sourcemeta::one::Action { router.arguments(identifier, [this](const auto &key, const auto &value) { if (key == "path") { this->file_root_ = std::get(value); + } else if (key == "errorSchema") { + this->error_schema_ = std::get(value); } }); } @@ -34,17 +36,18 @@ class ActionServeStatic_v1 : public sourcemeta::one::Action { sourcemeta::one::json_error( request, response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR, "missing-base-path", "The base path is not configured for this route", - std::string{this->base_path()} + "/self/v1/schemas/api/error"); + this->error_schema_); return; } ActionServeMetapackFile_v1::serve(this->file_root_ / matches.front(), sourcemeta::one::STATUS_OK, false, {}, {}, - request, response, this->base_path()); + request, response, this->error_schema_); } private: std::filesystem::path file_root_; + std::string_view error_schema_; }; #endif diff --git a/src/http/include/sourcemeta/one/http_helpers.h b/src/http/include/sourcemeta/one/http_helpers.h index 7d36cfc7..0b8d2b9a 100644 --- a/src/http/include/sourcemeta/one/http_helpers.h +++ b/src/http/include/sourcemeta/one/http_helpers.h @@ -53,7 +53,8 @@ inline auto send_response(const char *const code, const HTTPRequest &request, // See https://www.rfc-editor.org/rfc/rfc7807 inline auto json_error(const HTTPRequest &request, HTTPResponse &response, const char *const code, std::string &&identifier, - std::string &&message, std::string &&schema) -> void { + std::string &&message, const std::string_view schema) + -> void { auto object{sourcemeta::core::JSON::make_object()}; object.assign("title", sourcemeta::core::JSON{"sourcemeta:one/" + std::move(identifier)}); diff --git a/src/index/generators.h b/src/index/generators.h index 9b21ce13..d9040d12 100644 --- a/src/index/generators.h +++ b/src/index/generators.h @@ -677,12 +677,24 @@ struct GENERATE_URITEMPLATE_ROUTES { const auto metadata_schema{ configuration.base_path + "/self/v1/schemas/api/schemas/metadata/response"}; + const auto evaluate_response_schema{ + configuration.base_path + + "/self/v1/schemas/api/schemas/evaluate/response"}; + const auto trace_response_schema{ + configuration.base_path + + "/self/v1/schemas/api/schemas/trace/response"}; + const auto search_response_schema{ + configuration.base_path + + "/self/v1/schemas/api/schemas/search/response"}; + const auto error_schema{configuration.base_path + + "/self/v1/schemas/api/error"}; sourcemeta::core::URITemplateRouter::Identifier next_id{1}; const sourcemeta::core::URITemplateRouter::Argument list_arguments[] = { {"artifact", std::string_view{"directory"}}, - {"responseSchema", std::string_view{list_schema}}}; + {"responseSchema", std::string_view{list_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/list", next_id++, sourcemeta::one::ACTION_TYPE_EXPLORER_ARTIFACT_V1, list_arguments); @@ -693,75 +705,98 @@ struct GENERATE_URITEMPLATE_ROUTES { const sourcemeta::core::URITemplateRouter::Argument dependencies_arguments[] = { {"artifact", std::string_view{"dependencies"}}, - {"responseSchema", std::string_view{dependencies_schema}}}; + {"responseSchema", std::string_view{dependencies_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/dependencies/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, dependencies_arguments); const sourcemeta::core::URITemplateRouter::Argument dependents_arguments[] = {{"artifact", std::string_view{"dependents"}}, - {"responseSchema", std::string_view{dependents_schema}}}; + {"responseSchema", std::string_view{dependents_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/dependents/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, dependents_arguments); const sourcemeta::core::URITemplateRouter::Argument health_arguments[] = { {"artifact", std::string_view{"health"}}, - {"responseSchema", std::string_view{health_schema}}}; + {"responseSchema", std::string_view{health_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/health/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, health_arguments); const sourcemeta::core::URITemplateRouter::Argument locations_arguments[] = {{"artifact", std::string_view{"locations"}}, - {"responseSchema", std::string_view{locations_schema}}}; + {"responseSchema", std::string_view{locations_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/locations/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, locations_arguments); const sourcemeta::core::URITemplateRouter::Argument positions_arguments[] = {{"artifact", std::string_view{"positions"}}, - {"responseSchema", std::string_view{positions_schema}}}; + {"responseSchema", std::string_view{positions_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/positions/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, positions_arguments); const sourcemeta::core::URITemplateRouter::Argument stats_arguments[] = { {"artifact", std::string_view{"stats"}}, - {"responseSchema", std::string_view{stats_schema}}}; + {"responseSchema", std::string_view{stats_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/stats/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_SCHEMA_ARTIFACT_V1, stats_arguments); const sourcemeta::core::URITemplateRouter::Argument metadata_arguments[] = { {"artifact", std::string_view{"schema"}}, - {"responseSchema", std::string_view{metadata_schema}}}; + {"responseSchema", std::string_view{metadata_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/metadata/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_EXPLORER_ARTIFACT_V1, metadata_arguments); const sourcemeta::core::URITemplateRouter::Argument evaluate_arguments[] = { - {"mode", static_cast(0)}}; + {"mode", static_cast(0)}, + {"responseSchema", std::string_view{evaluate_response_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/evaluate/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_JSONSCHEMA_EVALUATE_V1, evaluate_arguments); const sourcemeta::core::URITemplateRouter::Argument trace_arguments[] = { - {"mode", static_cast(1)}}; + {"mode", static_cast(1)}, + {"responseSchema", std::string_view{trace_response_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/trace/{+schema}", next_id++, sourcemeta::one::ACTION_TYPE_JSONSCHEMA_EVALUATE_V1, trace_arguments); + const sourcemeta::core::URITemplateRouter::Argument search_arguments[] = { + {"responseSchema", std::string_view{search_response_schema}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/schemas/search", next_id++, - sourcemeta::one::ACTION_TYPE_SCHEMA_SEARCH_V1); + sourcemeta::one::ACTION_TYPE_SCHEMA_SEARCH_V1, search_arguments); + + const sourcemeta::core::URITemplateRouter::Argument + health_check_arguments[] = { + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/health", next_id++, - sourcemeta::one::ACTION_TYPE_HEALTH_CHECK_V1); + sourcemeta::one::ACTION_TYPE_HEALTH_CHECK_V1, + health_check_arguments); + + const sourcemeta::core::URITemplateRouter::Argument not_found_arguments[] = + {{"errorSchema", std::string_view{error_schema}}}; router.add("/self/v1/api/{+any}", next_id++, - sourcemeta::one::ACTION_TYPE_NOT_FOUND_V1); + sourcemeta::one::ACTION_TYPE_NOT_FOUND_V1, not_found_arguments); if (action.data == "Full") { const sourcemeta::core::URITemplateRouter::Argument static_arguments[] = { - {"path", std::string_view{SOURCEMETA_ONE_STATIC}}}; + {"path", std::string_view{SOURCEMETA_ONE_STATIC}}, + {"errorSchema", std::string_view{error_schema}}}; router.add("/self/static/{+path}", next_id++, sourcemeta::one::ACTION_TYPE_SERVE_STATIC_V1, static_arguments);