1919
2020#pragma once
2121
22+ #include < algorithm>
23+ #include < format>
2224#include < memory>
2325#include < string>
2426#include < unordered_map>
2830#include " iceberg/result.h"
2931#include " iceberg/table_identifier.h"
3032#include " iceberg/type_fwd.h"
33+ #include " iceberg/util/formatter_internal.h"
34+ #include " iceberg/util/macros.h"
3135
3236// / \file iceberg/catalog/rest/types.h
3337// / Request and response types for Iceberg REST Catalog API.
@@ -41,7 +45,13 @@ struct ICEBERG_REST_EXPORT CatalogConfig {
4145 std::vector<std::string> endpoints;
4246
4347 // / \brief Validates the CatalogConfig.
44- Status Validate () const ;
48+ Status Validate () const {
49+ // TODO(Li Feiyang): Add an invalidEndpoint test that validates endpoint format.
50+ // See:
51+ // https://github.com/apache/iceberg/blob/main/core/src/test/java/org/apache/iceberg/rest/responses/TestConfigResponseParser.java#L164
52+ // for reference.
53+ return {};
54+ }
4555};
4656
4757// / \brief JSON error payload returned in a response with further details on the error.
@@ -52,15 +62,28 @@ struct ICEBERG_REST_EXPORT ErrorModel {
5262 std::vector<std::string> stack;
5363
5464 // / \brief Validates the ErrorModel.
55- Status Validate () const ;
65+ Status Validate () const {
66+ if (message.empty () || type.empty ()) {
67+ return Invalid (" Invalid error model: missing required fields" );
68+ }
69+
70+ if (code < 400 || code > 600 ) {
71+ return Invalid (" Invalid error model: code {} is out of range [400, 600]" , code);
72+ }
73+
74+ // stack is optional, no validation needed
75+ return {};
76+ }
5677};
5778
5879// / \brief Error response body returned in a response.
5980struct ICEBERG_REST_EXPORT ErrorResponse {
6081 ErrorModel error; // required
6182
6283 // / \brief Validates the ErrorResponse.
63- Status Validate () const ;
84+ // We don't validate the error field because ErrorModel::Validate has been called in the
85+ // FromJson.
86+ Status Validate () const { return {}; }
6487};
6588
6689// / \brief Request to create a namespace.
@@ -69,7 +92,7 @@ struct ICEBERG_REST_EXPORT CreateNamespaceRequest {
6992 std::unordered_map<std::string, std::string> properties;
7093
7194 // / \brief Validates the CreateNamespaceRequest.
72- Status Validate () const ;
95+ Status Validate () const { return {}; }
7396};
7497
7598// / \brief Update or delete namespace properties request.
@@ -78,7 +101,38 @@ struct ICEBERG_REST_EXPORT UpdateNamespacePropertiesRequest {
78101 std::unordered_map<std::string, std::string> updates;
79102
80103 // / \brief Validates the UpdateNamespacePropertiesRequest.
81- Status Validate () const ;
104+ Status Validate () const {
105+ // keys in updates and removals must not overlap
106+ if (removals.empty () || updates.empty ()) {
107+ return {};
108+ }
109+
110+ auto extract_and_sort = [](const auto & container, auto key_extractor) {
111+ std::vector<std::string_view> result;
112+ result.reserve (container.size ());
113+ for (const auto & item : container) {
114+ result.push_back (std::string_view{key_extractor (item)});
115+ }
116+ std::ranges::sort (result);
117+ return result;
118+ };
119+
120+ auto sorted_removals =
121+ extract_and_sort (removals, [](const auto & s) -> const auto & { return s; });
122+ auto sorted_update_keys = extract_and_sort (
123+ updates, [](const auto & pair) -> const auto & { return pair.first ; });
124+
125+ std::vector<std::string_view> common;
126+ std::ranges::set_intersection (sorted_removals, sorted_update_keys,
127+ std::back_inserter (common));
128+
129+ if (!common.empty ()) {
130+ return Invalid (
131+ " Invalid namespace update: cannot simultaneously set and remove keys: {}" ,
132+ common);
133+ }
134+ return {};
135+ }
82136};
83137
84138// / \brief Request to register a table.
@@ -88,7 +142,17 @@ struct ICEBERG_REST_EXPORT RegisterTableRequest {
88142 bool overwrite = false ;
89143
90144 // / \brief Validates the RegisterTableRequest.
91- Status Validate () const ;
145+ Status Validate () const {
146+ if (name.empty ()) {
147+ return Invalid (" Missing table name" );
148+ }
149+
150+ if (metadata_location.empty ()) {
151+ return Invalid (" Empty metadata location" );
152+ }
153+
154+ return {};
155+ }
92156};
93157
94158// / \brief Request to rename a table.
@@ -97,7 +161,11 @@ struct ICEBERG_REST_EXPORT RenameTableRequest {
97161 TableIdentifier destination; // required
98162
99163 // / \brief Validates the RenameTableRequest.
100- Status Validate () const ;
164+ Status Validate () const {
165+ ICEBERG_RETURN_UNEXPECTED (source.Validate ());
166+ ICEBERG_RETURN_UNEXPECTED (destination.Validate ());
167+ return {};
168+ }
101169};
102170
103171// / \brief An opaque token that allows clients to make use of pagination for list APIs.
@@ -111,7 +179,12 @@ struct ICEBERG_REST_EXPORT LoadTableResult {
111179 // TODO(Li Feiyang): Add std::shared_ptr<StorageCredential> storage_credential;
112180
113181 // / \brief Validates the LoadTableResult.
114- Status Validate () const ;
182+ Status Validate () const {
183+ if (!metadata) {
184+ return Invalid (" Invalid metadata: null" );
185+ }
186+ return {};
187+ }
115188};
116189
117190// / \brief Alias of LoadTableResult used as the body of CreateTableResponse
@@ -126,7 +199,7 @@ struct ICEBERG_REST_EXPORT ListNamespacesResponse {
126199 std::vector<Namespace> namespaces;
127200
128201 // / \brief Validates the ListNamespacesResponse.
129- Status Validate () const ;
202+ Status Validate () const { return {}; }
130203};
131204
132205// / \brief Response body after creating a namespace.
@@ -135,7 +208,7 @@ struct ICEBERG_REST_EXPORT CreateNamespaceResponse {
135208 std::unordered_map<std::string, std::string> properties;
136209
137210 // / \brief Validates the CreateNamespaceResponse.
138- Status Validate () const ;
211+ Status Validate () const { return {}; }
139212};
140213
141214// / \brief Response body for loading namespace properties.
@@ -144,7 +217,7 @@ struct ICEBERG_REST_EXPORT GetNamespaceResponse {
144217 std::unordered_map<std::string, std::string> properties;
145218
146219 // / \brief Validates the GetNamespaceResponse.
147- Status Validate () const ;
220+ Status Validate () const { return {}; }
148221};
149222
150223// / \brief Response body after updating namespace properties.
@@ -154,7 +227,7 @@ struct ICEBERG_REST_EXPORT UpdateNamespacePropertiesResponse {
154227 std::vector<std::string> missing;
155228
156229 // / \brief Validates the UpdateNamespacePropertiesResponse.
157- Status Validate () const ;
230+ Status Validate () const { return {}; }
158231};
159232
160233// / \brief Response body for listing tables in a namespace.
@@ -163,7 +236,7 @@ struct ICEBERG_REST_EXPORT ListTablesResponse {
163236 std::vector<TableIdentifier> identifiers;
164237
165238 // / \brief Validates the ListTablesResponse.
166- Status Validate () const ;
239+ Status Validate () const { return {}; }
167240};
168241
169242} // namespace iceberg::rest
0 commit comments