mirror of
https://github.com/scylladb/scylladb.git
synced 2026-06-04 14:03:06 +00:00
alternator: clean up api_error() interface
All operation-generated error messages should have the 400 HTTP error code. It's a real nag to have to type it every time. So make it the default. Signed-off-by: Nadav Har'El <nyh@scylladb.com>
This commit is contained in:
@@ -139,12 +139,12 @@ static void validate_table_name(const sstring& name) {
|
||||
// are limited to 255 bytes, we need to limit table names to 222 bytes,
|
||||
// instead of 255.
|
||||
if (name.length() < 3 || name.length() > 222) {
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
"TableName must be at least 3 characters long and at most 222 characters long");
|
||||
}
|
||||
static std::regex valid_table_name_chars ("[a-zA-Z0-9_.-]*");
|
||||
if (!std::regex_match(name.c_str(), valid_table_name_chars)) {
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
"TableName must satisfy regular expression pattern: [a-zA-Z0-9_.-]+");
|
||||
}
|
||||
}
|
||||
@@ -157,7 +157,7 @@ future<json::json_return_type> executor::describe_table(sstring content) {
|
||||
sstring table_name = request["TableName"].asString();
|
||||
validate_table_name(table_name);
|
||||
if (!_proxy.get_db().local().has_schema(KEYSPACE, table_name)) {
|
||||
throw api_error(reply::status_type::bad_request, "ResourceNotFoundException",
|
||||
throw api_error("ResourceNotFoundException",
|
||||
format("Requested resource not found: Table: {} not found", table_name));
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ future<json::json_return_type> executor::delete_table(sstring content) {
|
||||
sstring table_name = request["TableName"].asString();
|
||||
validate_table_name(table_name);
|
||||
if (!_proxy.get_db().local().has_schema(KEYSPACE, table_name)) {
|
||||
throw api_error(reply::status_type::bad_request, "ResourceNotFoundException",
|
||||
throw api_error("ResourceNotFoundException",
|
||||
format("Requested resource not found: Table: {} not found", table_name));
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ static data_type parse_key_type(const std::string& type) {
|
||||
case 'N': return long_type; // FIXME: this actually needs to be a new number type, not long
|
||||
}
|
||||
}
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
format("Invalid key type '{}', can only be S, B or N.", type));
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ static void add_column(schema_builder& builder, const std::string& name, const J
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
format("KeySchema key '{}' missing in AttributeDefinitions", name));
|
||||
}
|
||||
|
||||
@@ -251,17 +251,17 @@ future<json::json_return_type> executor::create_table(sstring content) {
|
||||
// first must be a HASH, the optional second one can be a RANGE.
|
||||
// These key names must also be present in the attributes_definitions.
|
||||
if (!key_schema.isArray() || key_schema.size() < 1 || key_schema.size() > 2) {
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
"KeySchema must list exactly one or two key columns");
|
||||
}
|
||||
if (key_schema[0]["KeyType"] != "HASH") {
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
"First key in KeySchema must be a HASH key");
|
||||
}
|
||||
add_column(builder, key_schema[0]["AttributeName"].asString(), attribute_definitions, column_kind::partition_key);
|
||||
if (key_schema.size() == 2) {
|
||||
if (key_schema[1]["KeyType"] != "RANGE") {
|
||||
throw api_error(reply::status_type::bad_request, "ValidationException",
|
||||
throw api_error("ValidationException",
|
||||
"Second key in KeySchema must be a RANGE key");
|
||||
}
|
||||
add_column(builder, key_schema[1]["AttributeName"].asString(), attribute_definitions, column_kind::partition_key);
|
||||
@@ -277,7 +277,7 @@ future<json::json_return_type> executor::create_table(sstring content) {
|
||||
return make_ready_future<json::json_return_type>(make_jsonable(std::move(status)));
|
||||
}).handle_exception_type([table_name = std::move(table_name)] (exceptions::already_exists_exception&) {
|
||||
return make_exception_future<json::json_return_type>(
|
||||
api_error(reply::status_type::bad_request, "ResourceInUseException",
|
||||
api_error("ResourceInUseException",
|
||||
format("Table {} already exists", table_name)));
|
||||
});
|
||||
}
|
||||
@@ -314,7 +314,7 @@ future<json::json_return_type> executor::put_item(sstring content) {
|
||||
try {
|
||||
schema = _proxy.get_db().local().find_schema(KEYSPACE, table_name);
|
||||
} catch(no_such_column_family&) {
|
||||
throw api_error(reply::status_type::bad_request, "ResourceNotFoundException",
|
||||
throw api_error("ResourceNotFoundException",
|
||||
format("Requested resource not found: Table: {} not found", table_name));
|
||||
}
|
||||
partition_key pk = pk_from_json(item, schema);
|
||||
@@ -426,6 +426,8 @@ future<> executor::start() {
|
||||
return make_ready_future<>();
|
||||
}
|
||||
|
||||
// FIXME: the RF of this keyspace should be configurable: RF=1 makes
|
||||
// sense on test setups, but not on real clusters.
|
||||
auto ksm = keyspace_metadata::new_keyspace(KEYSPACE, "org.apache.cassandra.locator.SimpleStrategy", {{"replication_factor", "1"}}, true);
|
||||
return _mm.announce_new_keyspace(ksm, api::min_timestamp, false).handle_exception_type([] (exceptions::already_exists_exception& ignored) {});
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ inline std::vector<sstring> split(const sstring& text, const char* separator) {
|
||||
// DynamoDB HTTP error responses are structured as follows
|
||||
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html
|
||||
// Our handlers throw an exception to report an error. If the exception
|
||||
// is of type alternator_api_error, it unwrapped and properly reported to
|
||||
// is of type alternator::api_error, it unwrapped and properly reported to
|
||||
// the user directly. Other exceptions are unexpected, and reported as
|
||||
// Internal Server Error.
|
||||
class api_handler : public handler_base {
|
||||
@@ -54,9 +54,10 @@ public:
|
||||
} catch (api_error &ae) {
|
||||
ret = ae;
|
||||
} catch (...) {
|
||||
ret = api_error(reply::status_type::internal_server_error,
|
||||
ret = api_error(
|
||||
"Internal Server Error",
|
||||
format("Internal server error: {}", std::current_exception()));
|
||||
format("Internal server error: {}", std::current_exception()),
|
||||
reply::status_type::internal_server_error);
|
||||
}
|
||||
// FIXME: what is this version number?
|
||||
rep->_content += "{\"__type\":\"com.amazonaws.dynamodb.v20120810#" + ret._type + "\"," +
|
||||
@@ -113,7 +114,7 @@ void server::set_routes(routes& r) {
|
||||
} else if (op == "GetItem") {
|
||||
return _executor.local().get_item(req->content);
|
||||
}
|
||||
throw api_error(reply::status_type::bad_request, "UnknownOperationException",
|
||||
throw api_error("UnknownOperationException",
|
||||
format("Unsupported operation {}", op));
|
||||
});
|
||||
|
||||
|
||||
@@ -30,15 +30,15 @@ private:
|
||||
|
||||
// DynamoDB's error messages are described in detail in
|
||||
// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html
|
||||
// An error message has a "type", e.g., "ResourceNotFoundException", a coarser
|
||||
// HTTP code (in the above case, 400), and a human readable message. Eventually these
|
||||
// Ah An error message has a "type", e.g., "ResourceNotFoundException", a coarser
|
||||
// HTTP code (almost always, 400), and a human readable message. Eventually these
|
||||
// will be wrapped into a JSON object returned to the client.
|
||||
class api_error : public std::exception {
|
||||
public:
|
||||
reply::status_type _http_code;
|
||||
sstring _type;
|
||||
sstring _msg;
|
||||
api_error(reply::status_type http_code, sstring type, sstring msg)
|
||||
api_error(sstring type, sstring msg, reply::status_type http_code = reply::status_type::bad_request)
|
||||
: _http_code(std::move(http_code))
|
||||
, _type(std::move(type))
|
||||
, _msg(std::move(msg))
|
||||
|
||||
Reference in New Issue
Block a user