Skip to content

Commit 414a71a

Browse files
authored
Take most schemas as route arguments (#823)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 9658355 commit 414a71a

12 files changed

Lines changed: 183 additions & 100 deletions

src/actions/action_default_v1.h

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,21 @@
1616

1717
class ActionDefault_v1 : public sourcemeta::one::Action {
1818
public:
19-
ActionDefault_v1(const std::filesystem::path &base,
20-
const sourcemeta::core::URITemplateRouterView &router,
21-
const sourcemeta::core::URITemplateRouter::Identifier)
22-
: sourcemeta::one::Action{base, router.base_path()} {}
19+
ActionDefault_v1(
20+
const std::filesystem::path &base,
21+
const sourcemeta::core::URITemplateRouterView &router,
22+
const sourcemeta::core::URITemplateRouter::Identifier identifier)
23+
: sourcemeta::one::Action{base, router.base_path()} {
24+
// TODO: This implies the API is mounted
25+
this->error_schema_ =
26+
std::string{this->base_path()} + "/self/v1/schemas/api/error";
27+
28+
router.arguments(identifier, [this](const auto &key, const auto &value) {
29+
if (key == "errorSchema") {
30+
this->error_schema_ = std::get<std::string_view>(value);
31+
}
32+
});
33+
}
2334

2435
auto run(const std::span<std::string_view>,
2536
sourcemeta::one::HTTPRequest &request,
@@ -31,8 +42,7 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
3142
path[this->base_path().size()] != '/')) {
3243
sourcemeta::one::json_error(
3344
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
34-
"There is nothing at this URL",
35-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
45+
"There is nothing at this URL", this->error_schema_);
3646
return;
3747
}
3848

@@ -48,27 +58,26 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
4858
ActionServeMetapackFile_v1::serve(
4959
this->base() / "explorer" / "%" / "directory-html.metapack",
5060
sourcemeta::one::STATUS_OK, false, {}, {}, request, response,
51-
this->base_path());
61+
this->error_schema_);
5262
return;
5363
} else if (request.method() == "get" || request.method() == "head") {
5464
sourcemeta::one::json_error(
5565
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
56-
"There is nothing at this URL",
57-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
66+
"There is nothing at this URL", this->error_schema_);
5867
return;
5968
} else {
6069
sourcemeta::one::json_error(
6170
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
6271
"method-not-allowed", "This HTTP method is invalid for this URL",
63-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
72+
this->error_schema_);
6473
return;
6574
}
6675
}
6776

6877
if (path.ends_with(".json")) {
6978
ActionJSONSchemaServe_v1::serve(this->base(),
7079
path.substr(0, path.size() - 5), request,
71-
response, this->base_path());
80+
response, this->error_schema_);
7281
return;
7382
}
7483

@@ -80,31 +89,34 @@ class ActionDefault_v1 : public sourcemeta::one::Action {
8089
ActionServeMetapackFile_v1::serve(
8190
explorer_path / "schema-html.metapack",
8291
sourcemeta::one::STATUS_OK, false, {}, {}, request, response,
83-
this->base_path());
92+
this->error_schema_);
8493
} else {
8594
explorer_path /= "directory-html.metapack";
8695
if (std::filesystem::exists(explorer_path)) {
8796
ActionServeMetapackFile_v1::serve(
8897
explorer_path, sourcemeta::one::STATUS_OK, false, {}, {},
89-
request, response, this->base_path());
98+
request, response, this->error_schema_);
9099
} else {
91100
ActionServeMetapackFile_v1::serve(
92101
this->base() / "explorer" / "%" / "404.metapack",
93102
sourcemeta::one::STATUS_NOT_FOUND, false, {}, {}, request,
94-
response, this->base_path());
103+
response, this->error_schema_);
95104
}
96105
}
97106
} else {
98107
ActionJSONSchemaServe_v1::serve(this->base(), path, request, response,
99-
this->base_path());
108+
this->error_schema_);
100109
}
101110
} else {
102111
sourcemeta::one::json_error(
103112
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
104-
"There is nothing at this URL",
105-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
113+
"There is nothing at this URL", this->error_schema_);
106114
}
107115
}
116+
117+
private:
118+
// TODO: This should be a string view
119+
std::string error_schema_;
108120
};
109121

110122
#endif

src/actions/action_health_check_v1.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@
1313

1414
class ActionHealthCheck_v1 : public sourcemeta::one::Action {
1515
public:
16-
ActionHealthCheck_v1(const std::filesystem::path &base,
17-
const sourcemeta::core::URITemplateRouterView &router,
18-
const sourcemeta::core::URITemplateRouter::Identifier)
19-
: sourcemeta::one::Action{base, router.base_path()} {}
16+
ActionHealthCheck_v1(
17+
const std::filesystem::path &base,
18+
const sourcemeta::core::URITemplateRouterView &router,
19+
const sourcemeta::core::URITemplateRouter::Identifier identifier)
20+
: sourcemeta::one::Action{base, router.base_path()} {
21+
router.arguments(identifier, [this](const auto &key, const auto &value) {
22+
if (key == "errorSchema") {
23+
this->error_schema_ = std::get<std::string_view>(value);
24+
}
25+
});
26+
}
2027

2128
auto run(const std::span<std::string_view>,
2229
sourcemeta::one::HTTPRequest &request,
@@ -25,7 +32,7 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action {
2532
sourcemeta::one::json_error(
2633
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
2734
"method-not-allowed", "This HTTP method is invalid for this URL",
28-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
35+
this->error_schema_);
2936
return;
3037
}
3138

@@ -34,6 +41,9 @@ class ActionHealthCheck_v1 : public sourcemeta::one::Action {
3441
sourcemeta::one::send_response(sourcemeta::one::STATUS_OK, request,
3542
response);
3643
}
44+
45+
private:
46+
std::string_view error_schema_;
3747
};
3848

3949
#endif

src/actions/action_jsonschema_evaluate_v1.h

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
3434
router.arguments(identifier, [this](const auto &key, const auto &value) {
3535
if (key == "mode") {
3636
this->mode_ = static_cast<EvaluateMode>(std::get<std::int64_t>(value));
37+
} else if (key == "responseSchema") {
38+
this->response_schema_ = std::get<std::string_view>(value);
39+
} else if (key == "errorSchema") {
40+
this->error_schema_ = std::get<std::string_view>(value);
3741
}
3842
});
3943
}
@@ -64,12 +68,11 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
6468
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
6569
"no-template",
6670
"This schema was not precompiled for schema evaluation",
67-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
71+
this->error_schema_);
6872
} else {
6973
sourcemeta::one::json_error(
7074
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
71-
"There is nothing at this URL",
72-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
75+
"There is nothing at this URL", this->error_schema_);
7376
}
7477

7578
return;
@@ -92,16 +95,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
9295
sourcemeta::one::json_error(
9396
callback_request, callback_response,
9497
sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR,
95-
"uncaught-error", exception.what(),
96-
std::string{this->base_path()} +
97-
"/self/v1/schemas/api/error");
98+
"uncaught-error", exception.what(), this->error_schema_);
9899
}
99100
});
100101
} else {
101102
sourcemeta::one::json_error(
102103
request, response, sourcemeta::one::STATUS_METHOD_NOT_ALLOWED,
103104
"method-not-allowed", "This HTTP method is invalid for this URL",
104-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
105+
this->error_schema_);
105106
}
106107
}
107108

@@ -314,15 +315,14 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
314315
sourcemeta::one::json_error(
315316
request, response, sourcemeta::one::STATUS_PAYLOAD_TOO_LARGE,
316317
"payload-too-large", "The request body is too large",
317-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
318+
this->error_schema_);
318319
return;
319320
}
320321

321322
if (body.empty()) {
322323
sourcemeta::one::json_error(
323324
request, response, sourcemeta::one::STATUS_BAD_REQUEST, "no-instance",
324-
"You must pass an instance to validate against",
325-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
325+
"You must pass an instance to validate against", this->error_schema_);
326326
return;
327327
}
328328

@@ -331,15 +331,7 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
331331
response.write_status(sourcemeta::one::STATUS_OK);
332332
response.write_header("Content-Type", "application/json");
333333
response.write_header("Access-Control-Allow-Origin", "*");
334-
if (mode == EvaluateMode::Trace) {
335-
sourcemeta::one::write_link_header(
336-
response, std::string{this->base_path()} +
337-
"/self/v1/schemas/api/schemas/trace/response");
338-
} else {
339-
sourcemeta::one::write_link_header(
340-
response, std::string{this->base_path()} +
341-
"/self/v1/schemas/api/schemas/evaluate/response");
342-
}
334+
sourcemeta::one::write_link_header(response, this->response_schema_);
343335

344336
std::ostringstream payload;
345337
sourcemeta::core::prettify(result, payload);
@@ -349,12 +341,13 @@ class ActionJSONSchemaEvaluate_v1 : public sourcemeta::one::Action {
349341
} catch (const std::exception &exception) {
350342
sourcemeta::one::json_error(
351343
request, response, sourcemeta::one::STATUS_INTERNAL_SERVER_ERROR,
352-
"evaluation-error", exception.what(),
353-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
344+
"evaluation-error", exception.what(), this->error_schema_);
354345
}
355346
}
356347

357348
EvaluateMode mode_{EvaluateMode::Standard};
349+
std::string_view response_schema_;
350+
std::string_view error_schema_;
358351
};
359352

360353
#endif

src/actions/action_jsonschema_serve_v1.h

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,20 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action {
2121
ActionJSONSchemaServe_v1(
2222
const std::filesystem::path &base,
2323
const sourcemeta::core::URITemplateRouterView &router,
24-
const sourcemeta::core::URITemplateRouter::Identifier)
25-
: sourcemeta::one::Action{base, router.base_path()} {}
24+
const sourcemeta::core::URITemplateRouter::Identifier identifier)
25+
: sourcemeta::one::Action{base, router.base_path()} {
26+
router.arguments(identifier, [this](const auto &key, const auto &value) {
27+
if (key == "errorSchema") {
28+
this->error_schema_ = std::get<std::string_view>(value);
29+
}
30+
});
31+
}
2632

2733
static auto serve(const std::filesystem::path &base,
2834
std::string_view schema_path,
2935
sourcemeta::one::HTTPRequest &request,
3036
sourcemeta::one::HTTPResponse &response,
31-
std::string_view base_path = {}) -> void {
37+
std::string_view error_schema) -> void {
3238
// Otherwise we may get unexpected results in case-sensitive file-systems
3339
std::string lowercase_path{schema_path};
3440
std::ranges::transform(
@@ -56,28 +62,31 @@ class ActionJSONSchemaServe_v1 : public sourcemeta::one::Action {
5662
!std::filesystem::exists(absolute_path)) {
5763
sourcemeta::one::json_error(
5864
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
59-
"There is nothing at this URL",
60-
std::string{base_path} + "/self/v1/schemas/api/error");
65+
"There is nothing at this URL", error_schema);
6166
return;
6267
}
6368

6469
if (is_deno) {
6570
// For HTTP imports, as Deno won't like the `application/schema+json` one
6671
ActionServeMetapackFile_v1::serve(
6772
absolute_path, sourcemeta::one::STATUS_OK, true, "application/json",
68-
{}, request, response, base_path);
73+
{}, request, response, error_schema);
6974
} else {
7075
ActionServeMetapackFile_v1::serve(absolute_path,
7176
sourcemeta::one::STATUS_OK, true, {},
72-
{}, request, response, base_path);
77+
{}, request, response, error_schema);
7378
}
7479
}
7580

7681
auto run(const std::span<std::string_view> matches,
7782
sourcemeta::one::HTTPRequest &request,
7883
sourcemeta::one::HTTPResponse &response) -> void override {
79-
serve(this->base(), matches.front(), request, response, this->base_path());
84+
serve(this->base(), matches.front(), request, response,
85+
this->error_schema_);
8086
}
87+
88+
private:
89+
std::string_view error_schema_;
8190
};
8291

8392
#endif

src/actions/action_not_found_v1.h

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,28 @@
1313

1414
class ActionNotFound_v1 : public sourcemeta::one::Action {
1515
public:
16-
ActionNotFound_v1(const std::filesystem::path &base,
17-
const sourcemeta::core::URITemplateRouterView &router,
18-
const sourcemeta::core::URITemplateRouter::Identifier)
19-
: sourcemeta::one::Action{base, router.base_path()} {}
16+
ActionNotFound_v1(
17+
const std::filesystem::path &base,
18+
const sourcemeta::core::URITemplateRouterView &router,
19+
const sourcemeta::core::URITemplateRouter::Identifier identifier)
20+
: sourcemeta::one::Action{base, router.base_path()} {
21+
router.arguments(identifier, [this](const auto &key, const auto &value) {
22+
if (key == "errorSchema") {
23+
this->error_schema_ = std::get<std::string_view>(value);
24+
}
25+
});
26+
}
2027

2128
auto run(const std::span<std::string_view>,
2229
sourcemeta::one::HTTPRequest &request,
2330
sourcemeta::one::HTTPResponse &response) -> void override {
2431
sourcemeta::one::json_error(
2532
request, response, sourcemeta::one::STATUS_NOT_FOUND, "not-found",
26-
"There is nothing at this URL",
27-
std::string{this->base_path()} + "/self/v1/schemas/api/error");
33+
"There is nothing at this URL", this->error_schema_);
2834
}
35+
36+
private:
37+
std::string_view error_schema_;
2938
};
3039

3140
#endif

0 commit comments

Comments
 (0)