From 9ab791bedc2e94b8d5e4ae99bf0b4fa1a512ef6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lecrenier?= Date: Sun, 8 Jan 2023 13:03:23 +0100 Subject: [PATCH] Update error codes on the api key routes --- dump/src/reader/compat/v5_to_v6.rs | 2 +- meilisearch-types/src/error.rs | 28 +++++++++++- meilisearch-types/src/keys.rs | 18 +++++--- meilisearch/src/routes/api_key.rs | 72 ++++++++++++++++++++++++++++-- meilisearch/tests/auth/api_keys.rs | 12 ++--- 5 files changed, 114 insertions(+), 18 deletions(-) diff --git a/dump/src/reader/compat/v5_to_v6.rs b/dump/src/reader/compat/v5_to_v6.rs index 34132c030..571490980 100644 --- a/dump/src/reader/compat/v5_to_v6.rs +++ b/dump/src/reader/compat/v5_to_v6.rs @@ -291,7 +291,7 @@ impl From for v6::ResponseError { "malformed_payload" => v6::Code::MalformedPayload, "missing_payload" => v6::Code::MissingPayload, "api_key_not_found" => v6::Code::ApiKeyNotFound, - "missing_parameter" => v6::Code::MissingParameter, + "missing_parameter" => v6::Code::UnretrievableErrorCode, "invalid_api_key_actions" => v6::Code::InvalidApiKeyActions, "invalid_api_key_indexes" => v6::Code::InvalidApiKeyIndexes, "invalid_api_key_expires_at" => v6::Code::InvalidApiKeyExpiresAt, diff --git a/meilisearch-types/src/error.rs b/meilisearch-types/src/error.rs index 24fcc93bc..bd06e69e9 100644 --- a/meilisearch-types/src/error.rs +++ b/meilisearch-types/src/error.rs @@ -230,7 +230,13 @@ pub enum Code { MissingPayload, ApiKeyNotFound, - MissingParameter, + + MissingApiKeyActions, + MissingApiKeyExpiresAt, + MissingApiKeyIndexes, + + InvalidApiKeyOffset, + InvalidApiKeyLimit, InvalidApiKeyActions, InvalidApiKeyIndexes, InvalidApiKeyExpiresAt, @@ -362,7 +368,25 @@ impl Code { // error related to keys ApiKeyNotFound => ErrCode::invalid("api_key_not_found", StatusCode::NOT_FOUND), - MissingParameter => ErrCode::invalid("missing_parameter", StatusCode::BAD_REQUEST), + + MissingApiKeyExpiresAt => { + ErrCode::invalid("missing_api_key_expires_at", StatusCode::BAD_REQUEST) + } + + MissingApiKeyActions => { + ErrCode::invalid("missing_api_key_actions", StatusCode::BAD_REQUEST) + } + + MissingApiKeyIndexes => { + ErrCode::invalid("missing_api_key_indexes", StatusCode::BAD_REQUEST) + } + + InvalidApiKeyOffset => { + ErrCode::invalid("invalid_api_key_offset", StatusCode::BAD_REQUEST) + } + InvalidApiKeyLimit => { + ErrCode::invalid("invalid_api_key_limit", StatusCode::BAD_REQUEST) + } InvalidApiKeyActions => { ErrCode::invalid("invalid_api_key_actions", StatusCode::BAD_REQUEST) } diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 2ec624809..481678a83 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -60,7 +60,7 @@ impl Key { .map(|act| { from_value(act.clone()).map_err(|_| Error::InvalidApiKeyActions(act.clone())) }) - .ok_or(Error::MissingParameter("actions"))??; + .ok_or(Error::MissingApiKeyActions)??; let indexes = value .get("indexes") @@ -75,12 +75,12 @@ impl Key { .collect() }) }) - .ok_or(Error::MissingParameter("indexes"))??; + .ok_or(Error::MissingApiKeyIndexes)??; let expires_at = value .get("expiresAt") .map(parse_expiration_date) - .ok_or(Error::MissingParameter("expiresAt"))??; + .ok_or(Error::MissingApiKeyExpiresAt)??; let created_at = OffsetDateTime::now_utc(); let updated_at = created_at; @@ -344,8 +344,12 @@ pub mod actions { #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("`{0}` field is mandatory.")] - MissingParameter(&'static str), + #[error("`expiresAt` field is mandatory.")] + MissingApiKeyExpiresAt, + #[error("`indexes` field is mandatory.")] + MissingApiKeyIndexes, + #[error("`actions` field is mandatory.")] + MissingApiKeyActions, #[error("`actions` field value `{0}` is invalid. It should be an array of string representing action names.")] InvalidApiKeyActions(Value), #[error("`indexes` field value `{0}` is invalid. It should be an array of string representing index names.")] @@ -375,7 +379,9 @@ impl From for Error { impl ErrorCode for Error { fn error_code(&self) -> Code { match self { - Self::MissingParameter(_) => Code::MissingParameter, + Self::MissingApiKeyExpiresAt => Code::MissingApiKeyExpiresAt, + Self::MissingApiKeyIndexes => Code::MissingApiKeyIndexes, + Self::MissingApiKeyActions => Code::MissingApiKeyActions, Self::InvalidApiKeyActions(_) => Code::InvalidApiKeyActions, Self::InvalidApiKeyIndexes(_) | Self::InvalidApiKeyIndexUid(_) => { Code::InvalidApiKeyIndexes diff --git a/meilisearch/src/routes/api_key.rs b/meilisearch/src/routes/api_key.rs index b53fd3895..cd8a51662 100644 --- a/meilisearch/src/routes/api_key.rs +++ b/meilisearch/src/routes/api_key.rs @@ -1,9 +1,12 @@ -use std::str; +use std::convert::Infallible; +use std::num::ParseIntError; +use std::{fmt, str}; use actix_web::{web, HttpRequest, HttpResponse}; +use deserr::{DeserializeError, IntoValue, MergeWithError, ValuePointerRef}; use meilisearch_auth::error::AuthControllerError; use meilisearch_auth::AuthController; -use meilisearch_types::error::{Code, ResponseError}; +use meilisearch_types::error::{unwrap_any, Code, ErrorCode, ResponseError}; use meilisearch_types::keys::{Action, Key}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -12,6 +15,7 @@ use uuid::Uuid; use crate::extractors::authentication::policies::*; use crate::extractors::authentication::GuardedData; +use crate::extractors::query_parameters::QueryParameter; use crate::extractors::sequential_extractor::SeqHandler; use crate::routes::Pagination; @@ -45,10 +49,72 @@ pub async fn create_api_key( Ok(HttpResponse::Created().json(res)) } +#[derive(Debug)] +pub struct PaginationDeserrError { + error: String, + code: Code, +} + +impl std::fmt::Display for PaginationDeserrError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.error) + } +} + +impl std::error::Error for PaginationDeserrError {} +impl ErrorCode for PaginationDeserrError { + fn error_code(&self) -> Code { + self.code + } +} + +impl MergeWithError for PaginationDeserrError { + fn merge( + _self_: Option, + other: PaginationDeserrError, + _merge_location: ValuePointerRef, + ) -> Result { + Err(other) + } +} + +impl DeserializeError for PaginationDeserrError { + fn error( + _self_: Option, + error: deserr::ErrorKind, + location: ValuePointerRef, + ) -> Result { + let error = unwrap_any(deserr::serde_json::JsonError::error(None, error, location)).0; + + let code = match location.last_field() { + Some("offset") => Code::InvalidApiKeyLimit, + Some("limit") => Code::InvalidApiKeyOffset, + _ => Code::BadRequest, + }; + + Err(PaginationDeserrError { error, code }) + } +} + +impl MergeWithError for PaginationDeserrError { + fn merge( + _self_: Option, + other: ParseIntError, + merge_location: ValuePointerRef, + ) -> Result { + PaginationDeserrError::error::( + None, + deserr::ErrorKind::Unexpected { msg: other.to_string() }, + merge_location, + ) + } +} + pub async fn list_api_keys( auth_controller: GuardedData, AuthController>, - paginate: web::Query, + paginate: QueryParameter, ) -> Result { + let paginate = paginate.into_inner(); let page_view = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> { let keys = auth_controller.list_keys()?; let page_view = paginate diff --git a/meilisearch/tests/auth/api_keys.rs b/meilisearch/tests/auth/api_keys.rs index 80e5d01f6..72f7cdff1 100644 --- a/meilisearch/tests/auth/api_keys.rs +++ b/meilisearch/tests/auth/api_keys.rs @@ -245,9 +245,9 @@ async fn error_add_api_key_missing_parameter() { let expected_response = json!({ "message": "`indexes` field is mandatory.", - "code": "missing_parameter", + "code": "missing_api_key_indexes", "type": "invalid_request", - "link": "https://docs.meilisearch.com/errors#missing-parameter" + "link": "https://docs.meilisearch.com/errors#missing-api-key-indexes" }); assert_eq!(response, expected_response); @@ -263,9 +263,9 @@ async fn error_add_api_key_missing_parameter() { let expected_response = json!({ "message": "`actions` field is mandatory.", - "code": "missing_parameter", + "code": "missing_api_key_actions", "type": "invalid_request", - "link": "https://docs.meilisearch.com/errors#missing-parameter" + "link": "https://docs.meilisearch.com/errors#missing-api-key-actions" }); assert_eq!(response, expected_response); @@ -281,9 +281,9 @@ async fn error_add_api_key_missing_parameter() { let expected_response = json!({ "message": "`expiresAt` field is mandatory.", - "code": "missing_parameter", + "code": "missing_api_key_expires_at", "type": "invalid_request", - "link": "https://docs.meilisearch.com/errors#missing-parameter" + "link": "https://docs.meilisearch.com/errors#missing-api-key-expires-at" }); assert_eq!(response, expected_response);