Skip to content

Commit e36cf42

Browse files
committed
Add NoSuchKeyError as possible errorcode
Motivation: Such checks are best performed in backend than having client checking empty or null value. This is also in-line with more critical requirement for functioning of NotFound introduced by MonitorUpdatingPersister Design. Even though there are some popular KVStore's which do not throw such exception on keyNotFound such as AWS-DDB (arguably the most popular one), we can still figure out that key didn't exist if value was returned as null or by similar means in other stores.
1 parent 5fb2d6c commit e36cf42

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ fn main() {
1414
#[cfg(feature = "genproto")]
1515
fn generate_protos() {
1616
download_file(
17-
"https://raw.githubusercontent.com/lightningdevkit/vss-server/e1a88afd61f56d7e8e90a32036ca12389e36fe44/app/src/main/proto/vss.proto",
17+
"https://raw.githubusercontent.com/lightningdevkit/vss-server/d8991673f572408b7ea6a62627d9d30f03266876/app/src/main/proto/vss.proto",
1818
"src/proto/vss.proto",
1919
).unwrap();
2020

src/error.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,20 @@ use std::fmt::{Display, Formatter};
1010
/// information regarding each error code and corresponding use-cases.
1111
#[derive(Debug)]
1212
pub enum VssError {
13+
/// Refer [`ErrorCode::NoSuchKeyException`].
14+
NoSuchKeyError(String),
15+
16+
/// Refer [`ErrorCode::InvalidRequestException`].
1317
InvalidRequestError(String),
18+
19+
/// Refer [`ErrorCode::ConflictException`].
1420
ConflictError(String),
21+
22+
/// Refer [`ErrorCode::InternalServerException`].
1523
InternalServerError(String),
24+
25+
// There is an unknown error, it could be a client-side bug, unrecognized error-code, network error
26+
// or something else.
1627
InternalError(String),
1728
}
1829

@@ -33,6 +44,9 @@ impl VssError {
3344
impl Display for VssError {
3445
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
3546
match self {
47+
VssError::NoSuchKeyError(message) => {
48+
write!(f, "Requested key does not exist: {}", message)
49+
}
3650
VssError::InvalidRequestError(message) => {
3751
write!(f, "Request sent to VSS Storage was invalid: {}", message)
3852
}
@@ -54,6 +68,7 @@ impl Error for VssError {}
5468
impl From<ErrorResponse> for VssError {
5569
fn from(error_response: ErrorResponse) -> Self {
5670
match error_response.error_code() {
71+
ErrorCode::NoSuchKeyException => VssError::NoSuchKeyError(error_response.message),
5772
ErrorCode::InvalidRequestException => VssError::InvalidRequestError(error_response.message),
5873
ErrorCode::ConflictException => VssError::ConflictError(error_response.message),
5974
ErrorCode::InternalServerException => VssError::InternalServerError(error_response.message),

src/types.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub struct GetObjectRequest {
1212
pub store_id: ::prost::alloc::string::String,
1313
/// `Key` for which the value is to be fetched.
1414
///
15+
/// If the specified `key` does not exist, returns `ErrorResponse` with `NO_SUCH_KEY_EXCEPTION` as
16+
/// `ErrorCode`.
17+
///
1518
/// Consistency Guarantee:
1619
/// Get(read) operations against a `key` are consistent reads and will reflect all previous writes,
1720
/// since Put/Write provides read-after-write and read-after-update consistency guarantees.
@@ -298,6 +301,8 @@ pub enum ErrorCode {
298301
/// An internal server error occurred, client is probably at no fault and can safely retry this
299302
/// error with exponential backoff.
300303
InternalServerException = 3,
304+
/// NO_SUCH_KEY_EXCEPTION is used when the specified `key` in a `GetObjectRequest` does not exist.
305+
NoSuchKeyException = 4,
301306
}
302307
impl ErrorCode {
303308
/// String value of the enum field names used in the ProtoBuf definition.
@@ -310,6 +315,7 @@ impl ErrorCode {
310315
ErrorCode::ConflictException => "CONFLICT_EXCEPTION",
311316
ErrorCode::InvalidRequestException => "INVALID_REQUEST_EXCEPTION",
312317
ErrorCode::InternalServerException => "INTERNAL_SERVER_EXCEPTION",
318+
ErrorCode::NoSuchKeyException => "NO_SUCH_KEY_EXCEPTION",
313319
}
314320
}
315321
/// Creates an enum from field names used in the ProtoBuf definition.
@@ -319,6 +325,7 @@ impl ErrorCode {
319325
"CONFLICT_EXCEPTION" => Some(Self::ConflictException),
320326
"INVALID_REQUEST_EXCEPTION" => Some(Self::InvalidRequestException),
321327
"INTERNAL_SERVER_EXCEPTION" => Some(Self::InternalServerException),
328+
"NO_SUCH_KEY_EXCEPTION" => Some(Self::NoSuchKeyException),
322329
_ => None,
323330
}
324331
}

tests/tests.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,30 @@ mod tests {
149149
mock_server.expect(1).assert();
150150
}
151151

152+
#[tokio::test]
153+
async fn test_no_such_key_err_handling() {
154+
let base_url = mockito::server_url();
155+
let vss_client = VssClient::new(&base_url);
156+
157+
// NoSuchKeyError
158+
let error_response = ErrorResponse {
159+
error_code: ErrorCode::NoSuchKeyException.into(),
160+
message: "NoSuchKeyException".to_string(),
161+
};
162+
let mock_server = mockito::mock("POST", GET_OBJECT_ENDPOINT)
163+
.with_status(409)
164+
.with_body(&error_response.encode_to_vec())
165+
.create();
166+
167+
let get_result = vss_client
168+
.get_object(&GetObjectRequest { store_id: "store".to_string(), key: "non_existent_key".to_string() })
169+
.await;
170+
assert!(matches!(get_result.unwrap_err(), VssError::NoSuchKeyError { .. }));
171+
172+
// Verify 1 request hit the server
173+
mock_server.expect(1).assert();
174+
}
175+
152176
#[tokio::test]
153177
async fn test_invalid_request_err_handling() {
154178
let base_url = mockito::server_url();

0 commit comments

Comments
 (0)