Skip to content

Commit 32a2523

Browse files
Merge pull request #29563 from michael-redpanda/sr/contexts/core-15196
CORE-15196 - Add support for `referenceFormat`
2 parents e321e2b + 38ad128 commit 32a2523

File tree

7 files changed

+263
-10
lines changed

7 files changed

+263
-10
lines changed

src/v/pandaproxy/api/api-doc/schema_registry.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,13 @@
461461
"required": false,
462462
"type": "string",
463463
"description": "Optional qualified subject to search for the schema under. Use <:.context:> for context-only lookup, or <:.context:subject> to also verify the schema is associated with that subject. Defaults to searching the default context if unspecified."
464+
},
465+
{
466+
"name": "referenceFormat",
467+
"in": "query",
468+
"required": false,
469+
"type": "string",
470+
"description": "If set to 'qualified', schema references are returned in context-qualified form. Otherwise, unqualified references are returned."
464471
}
465472
],
466473
"produces": [

src/v/pandaproxy/schema_registry/handlers.cc

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ output_format parse_output_format(const ss::http::request& req) {
9696
.value_or(output_format::none);
9797
}
9898

99+
reference_format parse_reference_format(const ss::http::request& req) {
100+
return parse::query_param<std::optional<ss::sstring>>(
101+
req, "referenceFormat")
102+
.and_then(&from_string_view<reference_format>)
103+
.value_or(reference_format::none);
104+
}
105+
99106
template<ppj::impl::RjsonParseHandler Handler>
100107
typename ss::future<typename Handler::rjson_parse_result>
101108
rjson_parse(ss::http::request& req, Handler handler) {
@@ -1046,6 +1053,7 @@ ss::future<ctx_server<service>::reply_t> get_subject_versions_version(
10461053
parse::query_param<std::optional<include_deleted>>(*rq.req, "deleted")
10471054
.value_or(include_deleted::no)};
10481055
const auto format = parse_output_format(*rq.req);
1056+
const auto reference_format = parse_reference_format(*rq.req);
10491057

10501058
co_await rq.service().writer().read_sync();
10511059

@@ -1061,12 +1069,14 @@ ss::future<ctx_server<service>::reply_t> get_subject_versions_version(
10611069
std::move(def), format);
10621070

10631071
auto resp = ppj::rjson_serialize_iobuf(
1064-
get_subject_versions_version_response{.stored_schema{
1065-
.schema = {std::move(subject), std::move(formatted_schema)},
1066-
.version = get_res.version,
1067-
.id = get_res.id,
1068-
.deleted = get_res.deleted,
1069-
}});
1072+
get_subject_versions_version_response{
1073+
.stored_schema{
1074+
.schema = {std::move(subject), std::move(formatted_schema)},
1075+
.version = get_res.version,
1076+
.id = get_res.id,
1077+
.deleted = get_res.deleted,
1078+
},
1079+
.format = reference_format});
10701080
log_response(*rq.req, resp);
10711081
rp.rep->write_body("json", ppj::as_body_writer(std::move(resp)));
10721082
co_return rp;

src/v/pandaproxy/schema_registry/requests/get_subject_versions_version.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@
1313

1414
#include "json/iobuf_writer.h"
1515
#include "pandaproxy/schema_registry/rjson.h"
16+
#include "pandaproxy/schema_registry/types.h"
1617

1718
namespace pandaproxy::schema_registry {
1819

1920
struct get_subject_versions_version_response {
2021
stored_schema stored_schema;
22+
reference_format format{reference_format::none};
2123
};
2224

2325
template<typename Buffer>
2426
void rjson_serialize(
2527
::json::iobuf_writer<Buffer>& w,
2628
const get_subject_versions_version_response& res) {
2729
w.StartObject();
30+
bool is_qualified = res.stored_schema.schema.sub().ctx != default_context;
2831
w.Key("subject");
2932
w.String(res.stored_schema.schema.sub().to_string());
3033
w.Key("version");
@@ -36,7 +39,13 @@ void rjson_serialize(
3639
::json::rjson_serialize(w, to_string_view(type));
3740
if (!res.stored_schema.schema.def().refs().empty()) {
3841
w.Key("references");
39-
::json::rjson_serialize(w, res.stored_schema.schema.def().refs());
42+
::json::rjson_serialize(
43+
w,
44+
res.stored_schema.schema.def().refs(),
45+
is_qualified && res.format == reference_format::qualified
46+
? std::make_optional<std::reference_wrapper<const context>>(
47+
res.stored_schema.schema.sub().ctx)
48+
: std::nullopt);
4049
}
4150
::json::rjson_serialize(w, res.stored_schema.schema.def().meta());
4251
w.Key("schema");

src/v/pandaproxy/schema_registry/rjson.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,40 @@ void rjson_serialize(
2626

2727
template<typename Writer>
2828
void rjson_serialize(
29-
Writer& w, const pandaproxy::schema_registry::schema_reference& ref) {
29+
Writer& w,
30+
const pandaproxy::schema_registry::schema_reference& ref,
31+
std::optional<
32+
std::reference_wrapper<const pandaproxy::schema_registry::context>> ctx
33+
= std::nullopt) {
3034
w.StartObject();
3135
w.Key("name");
3236
::json::rjson_serialize(w, ref.name);
3337
w.Key("subject");
34-
w.String(ref.sub.to_string());
38+
if (ctx.has_value()) {
39+
w.String(ref.sub.resolve(ctx->get()).to_string());
40+
} else {
41+
w.String(ref.sub.to_string());
42+
}
43+
3544
w.Key("version");
3645
::json::rjson_serialize(w, ref.version);
3746
w.EndObject();
3847
}
3948

49+
template<typename Writer>
50+
void rjson_serialize(
51+
Writer& w,
52+
const pandaproxy::schema_registry::schema_definition::references& refs,
53+
std::optional<
54+
std::reference_wrapper<const pandaproxy::schema_registry::context>> ctx
55+
= std::nullopt) {
56+
w.StartArray();
57+
for (const auto& ref : refs) {
58+
rjson_serialize(w, ref, ctx);
59+
}
60+
w.EndArray();
61+
}
62+
4063
template<typename Writer>
4164
void rjson_serialize(
4265
Writer& w,

src/v/pandaproxy/schema_registry/types.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ std::ostream& operator<<(std::ostream& os, const output_format& v) {
2828
return os << to_string_view(v);
2929
}
3030

31+
std::ostream& operator<<(std::ostream& os, const reference_format& v) {
32+
return os << to_string_view(v);
33+
}
34+
3135
std::ostream& operator<<(std::ostream& os, const seq_marker& v) {
3236
if (v.seq.has_value() && v.node.has_value()) {
3337
fmt::print(

src/v/pandaproxy/schema_registry/types.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,31 @@ from_string_view<output_format>(std::string_view sv) {
124124

125125
std::ostream& operator<<(std::ostream& os, const output_format& of);
126126

127+
enum class reference_format { none = 0, qualified };
128+
129+
constexpr std::string_view to_string_view(reference_format rf) {
130+
switch (rf) {
131+
case reference_format::qualified:
132+
return "qualified";
133+
case reference_format::none:
134+
break;
135+
}
136+
return "";
137+
}
138+
139+
template<>
140+
inline std::optional<reference_format>
141+
from_string_view<reference_format>(std::string_view sv) {
142+
return string_switch<std::optional<reference_format>>(sv)
143+
.match(to_string_view(reference_format::none), reference_format::none)
144+
.match(
145+
to_string_view(reference_format::qualified),
146+
reference_format::qualified)
147+
.default_match(std::nullopt);
148+
}
149+
150+
std::ostream& operator<<(std::ostream& os, const reference_format& rf);
151+
127152
///\brief Type representing a global resource for ACLs.
128153
using registry_resource = named_type<ss::sstring, struct registry_resource_tag>;
129154

0 commit comments

Comments
 (0)