From c56d784864d8d1a9e5baf4650ba64646a6d79bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20M=C3=BCller?= Date: Sat, 16 Dec 2023 20:58:00 -0800 Subject: [PATCH] Rename omnipresent AuthenticationFailed error to NotPermitted The omnipresent AuthenticationFailed error variant, which used to map to HTTP status 401 (Unauthorized) had not been hooked up for ages, after Alpaca in their endless wisdom decided to move everything to using HTTP status 403, causing ambiguity all over the place. With this change we rename this variant to NotPermitted and map it to HTTP status 403. As part of this work, we effectively replace/overlay the recently introduced NotPermitted variants for the various data::v2 endpoint errors. --- CHANGELOG.md | 5 ++++- src/api/v2/account.rs | 3 +-- src/api/v2/clock.rs | 3 +-- src/api/v2/order.rs | 19 +------------------ src/data/v2/bars.rs | 3 --- src/data/v2/last_quotes.rs | 3 --- src/data/v2/quotes.rs | 3 --- src/data/v2/trades.rs | 3 --- src/endpoint.rs | 15 ++++++++++----- 9 files changed, 17 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45d2c760..1ec08b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ Unreleased ---------- - Removed `ApiError::code` member after endpoint reported errors stopped returning it -- Added `NotPermitted` variant to various `data::v2` endpoint errors +- Renamed `AuthenticationFailed` variant of endpoint errors to + `NotPermitted` + - This variant is now used to signal a multitude of conditions, + including certain order submission issues 0.27.2 diff --git a/src/api/v2/account.rs b/src/api/v2/account.rs index fc3e14b6..939bd2b1 100644 --- a/src/api/v2/account.rs +++ b/src/api/v2/account.rs @@ -248,7 +248,6 @@ mod tests { /// Check that we get back the expected error when requesting account /// data with invalid credentials. #[test(tokio::test)] - #[ignore] async fn request_account_with_invalid_credentials() { let api_info = ApiInfo::from_parts(API_BASE_URL, "invalid", "invalid-too").unwrap(); let client = Client::new(api_info); @@ -256,7 +255,7 @@ mod tests { let err = result.unwrap_err(); match err { - RequestError::Endpoint(GetError::AuthenticationFailed(_)) => (), + RequestError::Endpoint(GetError::NotPermitted(_)) => (), e => panic!("received unexpected error: {e:?}"), } } diff --git a/src/api/v2/clock.rs b/src/api/v2/clock.rs index 7e417b88..cbcad1ff 100644 --- a/src/api/v2/clock.rs +++ b/src/api/v2/clock.rs @@ -111,7 +111,6 @@ mod tests { /// Check that we get back the expected error when requesting the /// market clock with invalid credentials. #[test(tokio::test)] - #[ignore] async fn request_clock_with_invalid_credentials() { let api_info = ApiInfo::from_parts(API_BASE_URL, "invalid", "invalid-too").unwrap(); let client = Client::new(api_info); @@ -119,7 +118,7 @@ mod tests { let err = result.unwrap_err(); match err { - RequestError::Endpoint(GetError::AuthenticationFailed(_)) => (), + RequestError::Endpoint(GetError::NotPermitted(_)) => (), e => panic!("received unexpected error: {e:?}"), } } diff --git a/src/api/v2/order.rs b/src/api/v2/order.rs index f31ab2a6..0895c517 100644 --- a/src/api/v2/order.rs +++ b/src/api/v2/order.rs @@ -717,14 +717,6 @@ Endpoint! { /* 200 */ OK, ], Err => PostError, [ - /// The order submission was not permitted. That can have multiple - /// reasons, including (but not necessarily limited to): - /// - not enough funds are available - /// - the order is of a certain order type that cannot be submitted - /// at this time of day (e.g., market-open orders must be - /// submitted after 7:00pm and before 9:28am and will be rejected - /// at other times) - /* 403 */ FORBIDDEN => NotPermitted, /// Some data in the request was invalid. /* 422 */ UNPROCESSABLE_ENTITY => InvalidInput, ] @@ -756,14 +748,6 @@ Endpoint! { /* 200 */ OK, ], Err => PatchError, [ - /// The order change was not permitted. That can have multiple - /// reasons, including (but not necessarily limited to): - /// - not enough funds are available - /// - the order is of a certain order type that cannot be submitted - /// at this time of day (e.g., market-open orders must be - /// submitted after 7:00pm and before 9:28am and will be rejected - /// at other times) - /* 403 */ FORBIDDEN => NotPermitted, /// No order was found with the given ID. /* 404 */ NOT_FOUND => NotFound, /// Some data in the request was invalid. @@ -1067,8 +1051,7 @@ mod tests { // When an extended hours order is submitted between 6pm and 8pm, // the Alpaca API reports an error: - // > {"code":42210000,"message":"extended hours orders between 6:00pm - // > and 8:00pm is not supported"} + // > {"message":"extended hours orders between 6:00pm and 8:00pm is not supported"} // // So we need to treat this case specially. let result = test(true).await; diff --git a/src/data/v2/bars.rs b/src/data/v2/bars.rs index b540f086..31af6db2 100644 --- a/src/data/v2/bars.rs +++ b/src/data/v2/bars.rs @@ -178,9 +178,6 @@ Endpoint! { Err => GetError, [ /// A query parameter was invalid. /* 400 */ BAD_REQUEST => InvalidInput, - /// The request was not permitted. Possible reasons include usage of - /// the SIP feed without having the corresponding subscription. - /* 403 */ FORBIDDEN => NotPermitted, ] fn base_url() -> Option { diff --git a/src/data/v2/last_quotes.rs b/src/data/v2/last_quotes.rs index 2aaf527a..289964b9 100644 --- a/src/data/v2/last_quotes.rs +++ b/src/data/v2/last_quotes.rs @@ -92,9 +92,6 @@ EndpointNoParse! { /// The provided symbol was invalid or not found or the data feed is /// not supported. /* 400 */ BAD_REQUEST => InvalidInput, - /// The request was not permitted. Possible reasons include usage of - /// the SIP feed without having the corresponding subscription. - /* 403 */ FORBIDDEN => NotPermitted, ] fn base_url() -> Option { diff --git a/src/data/v2/quotes.rs b/src/data/v2/quotes.rs index 46af2155..e1e42284 100644 --- a/src/data/v2/quotes.rs +++ b/src/data/v2/quotes.rs @@ -104,9 +104,6 @@ Endpoint! { Err => GetError, [ /// Some of the provided data was invalid or not found. /* 400 */ BAD_REQUEST => InvalidInput, - /// The request was not permitted. Possible reasons include usage of - /// the SIP feed without having the corresponding subscription. - /* 403 */ FORBIDDEN => NotPermitted, ] fn base_url() -> Option { diff --git a/src/data/v2/trades.rs b/src/data/v2/trades.rs index c3bdf3ff..82d3db46 100644 --- a/src/data/v2/trades.rs +++ b/src/data/v2/trades.rs @@ -118,9 +118,6 @@ Endpoint! { Err => GetError, [ /// A query parameter was invalid. /* 400 */ BAD_REQUEST => InvalidInput, - /// The request was not permitted. Possible reasons include usage of - /// the SIP feed without having the corresponding subscription. - /* 403 */ FORBIDDEN => NotPermitted, ] fn base_url() -> Option { diff --git a/src/endpoint.rs b/src/endpoint.rs index 6f7bf1fc..d1649042 100644 --- a/src/endpoint.rs +++ b/src/endpoint.rs @@ -48,11 +48,16 @@ macro_rules! EndpointNoParse { // Every request can result in an authentication failure or fall // prey to the rate limit and so we include these variants into // all our error definitions. - /// Authentication failed for the request. - // TODO: This status actually got changed to 403, which now - // shadows other error conditions by specific endpoints - // (e.g., insufficient funds when submitting an order). - /* 401 */ UNAUTHORIZED => AuthenticationFailed, + /// The request was not permitted. + /// + /// This can have a multitude of reasons, including invalid + /// credentials or the (potentially implicit) request of SIP + /// data through the data APIs when only an IEX subscription is + /// available. + /// Order submission/change failure (e.g., due to insufficient + /// funds or time constraint violations) is also expressed this + /// way. + /* 403 */ FORBIDDEN => NotPermitted, /// The rate limit was exceeded, causing the request to be /// denied. /* 429 */ TOO_MANY_REQUESTS => RateLimitExceeded,