Update error codes on the api key routes

This commit is contained in:
Loïc Lecrenier 2023-01-08 13:03:23 +01:00 committed by Tamo
parent 96105a5e8d
commit 9ab791bedc
5 changed files with 114 additions and 18 deletions

View File

@ -291,7 +291,7 @@ impl From<v5::ResponseError> for v6::ResponseError {
"malformed_payload" => v6::Code::MalformedPayload, "malformed_payload" => v6::Code::MalformedPayload,
"missing_payload" => v6::Code::MissingPayload, "missing_payload" => v6::Code::MissingPayload,
"api_key_not_found" => v6::Code::ApiKeyNotFound, "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_actions" => v6::Code::InvalidApiKeyActions,
"invalid_api_key_indexes" => v6::Code::InvalidApiKeyIndexes, "invalid_api_key_indexes" => v6::Code::InvalidApiKeyIndexes,
"invalid_api_key_expires_at" => v6::Code::InvalidApiKeyExpiresAt, "invalid_api_key_expires_at" => v6::Code::InvalidApiKeyExpiresAt,

View File

@ -230,7 +230,13 @@ pub enum Code {
MissingPayload, MissingPayload,
ApiKeyNotFound, ApiKeyNotFound,
MissingParameter,
MissingApiKeyActions,
MissingApiKeyExpiresAt,
MissingApiKeyIndexes,
InvalidApiKeyOffset,
InvalidApiKeyLimit,
InvalidApiKeyActions, InvalidApiKeyActions,
InvalidApiKeyIndexes, InvalidApiKeyIndexes,
InvalidApiKeyExpiresAt, InvalidApiKeyExpiresAt,
@ -362,7 +368,25 @@ impl Code {
// error related to keys // error related to keys
ApiKeyNotFound => ErrCode::invalid("api_key_not_found", StatusCode::NOT_FOUND), 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 => { InvalidApiKeyActions => {
ErrCode::invalid("invalid_api_key_actions", StatusCode::BAD_REQUEST) ErrCode::invalid("invalid_api_key_actions", StatusCode::BAD_REQUEST)
} }

View File

@ -60,7 +60,7 @@ impl Key {
.map(|act| { .map(|act| {
from_value(act.clone()).map_err(|_| Error::InvalidApiKeyActions(act.clone())) from_value(act.clone()).map_err(|_| Error::InvalidApiKeyActions(act.clone()))
}) })
.ok_or(Error::MissingParameter("actions"))??; .ok_or(Error::MissingApiKeyActions)??;
let indexes = value let indexes = value
.get("indexes") .get("indexes")
@ -75,12 +75,12 @@ impl Key {
.collect() .collect()
}) })
}) })
.ok_or(Error::MissingParameter("indexes"))??; .ok_or(Error::MissingApiKeyIndexes)??;
let expires_at = value let expires_at = value
.get("expiresAt") .get("expiresAt")
.map(parse_expiration_date) .map(parse_expiration_date)
.ok_or(Error::MissingParameter("expiresAt"))??; .ok_or(Error::MissingApiKeyExpiresAt)??;
let created_at = OffsetDateTime::now_utc(); let created_at = OffsetDateTime::now_utc();
let updated_at = created_at; let updated_at = created_at;
@ -344,8 +344,12 @@ pub mod actions {
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error("`{0}` field is mandatory.")] #[error("`expiresAt` field is mandatory.")]
MissingParameter(&'static str), 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.")] #[error("`actions` field value `{0}` is invalid. It should be an array of string representing action names.")]
InvalidApiKeyActions(Value), InvalidApiKeyActions(Value),
#[error("`indexes` field value `{0}` is invalid. It should be an array of string representing index names.")] #[error("`indexes` field value `{0}` is invalid. It should be an array of string representing index names.")]
@ -375,7 +379,9 @@ impl From<IndexUidFormatError> for Error {
impl ErrorCode for Error { impl ErrorCode for Error {
fn error_code(&self) -> Code { fn error_code(&self) -> Code {
match self { match self {
Self::MissingParameter(_) => Code::MissingParameter, Self::MissingApiKeyExpiresAt => Code::MissingApiKeyExpiresAt,
Self::MissingApiKeyIndexes => Code::MissingApiKeyIndexes,
Self::MissingApiKeyActions => Code::MissingApiKeyActions,
Self::InvalidApiKeyActions(_) => Code::InvalidApiKeyActions, Self::InvalidApiKeyActions(_) => Code::InvalidApiKeyActions,
Self::InvalidApiKeyIndexes(_) | Self::InvalidApiKeyIndexUid(_) => { Self::InvalidApiKeyIndexes(_) | Self::InvalidApiKeyIndexUid(_) => {
Code::InvalidApiKeyIndexes Code::InvalidApiKeyIndexes

View File

@ -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 actix_web::{web, HttpRequest, HttpResponse};
use deserr::{DeserializeError, IntoValue, MergeWithError, ValuePointerRef};
use meilisearch_auth::error::AuthControllerError; use meilisearch_auth::error::AuthControllerError;
use meilisearch_auth::AuthController; 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 meilisearch_types::keys::{Action, Key};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
@ -12,6 +15,7 @@ use uuid::Uuid;
use crate::extractors::authentication::policies::*; use crate::extractors::authentication::policies::*;
use crate::extractors::authentication::GuardedData; use crate::extractors::authentication::GuardedData;
use crate::extractors::query_parameters::QueryParameter;
use crate::extractors::sequential_extractor::SeqHandler; use crate::extractors::sequential_extractor::SeqHandler;
use crate::routes::Pagination; use crate::routes::Pagination;
@ -45,10 +49,72 @@ pub async fn create_api_key(
Ok(HttpResponse::Created().json(res)) 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<PaginationDeserrError> for PaginationDeserrError {
fn merge(
_self_: Option<Self>,
other: PaginationDeserrError,
_merge_location: ValuePointerRef,
) -> Result<Self, Self> {
Err(other)
}
}
impl DeserializeError for PaginationDeserrError {
fn error<V: IntoValue>(
_self_: Option<Self>,
error: deserr::ErrorKind<V>,
location: ValuePointerRef,
) -> Result<Self, Self> {
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<ParseIntError> for PaginationDeserrError {
fn merge(
_self_: Option<Self>,
other: ParseIntError,
merge_location: ValuePointerRef,
) -> Result<Self, Self> {
PaginationDeserrError::error::<Infallible>(
None,
deserr::ErrorKind::Unexpected { msg: other.to_string() },
merge_location,
)
}
}
pub async fn list_api_keys( pub async fn list_api_keys(
auth_controller: GuardedData<ActionPolicy<{ actions::KEYS_GET }>, AuthController>, auth_controller: GuardedData<ActionPolicy<{ actions::KEYS_GET }>, AuthController>,
paginate: web::Query<Pagination>, paginate: QueryParameter<Pagination, PaginationDeserrError>,
) -> Result<HttpResponse, ResponseError> { ) -> Result<HttpResponse, ResponseError> {
let paginate = paginate.into_inner();
let page_view = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> { let page_view = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> {
let keys = auth_controller.list_keys()?; let keys = auth_controller.list_keys()?;
let page_view = paginate let page_view = paginate

View File

@ -245,9 +245,9 @@ async fn error_add_api_key_missing_parameter() {
let expected_response = json!({ let expected_response = json!({
"message": "`indexes` field is mandatory.", "message": "`indexes` field is mandatory.",
"code": "missing_parameter", "code": "missing_api_key_indexes",
"type": "invalid_request", "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); assert_eq!(response, expected_response);
@ -263,9 +263,9 @@ async fn error_add_api_key_missing_parameter() {
let expected_response = json!({ let expected_response = json!({
"message": "`actions` field is mandatory.", "message": "`actions` field is mandatory.",
"code": "missing_parameter", "code": "missing_api_key_actions",
"type": "invalid_request", "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); assert_eq!(response, expected_response);
@ -281,9 +281,9 @@ async fn error_add_api_key_missing_parameter() {
let expected_response = json!({ let expected_response = json!({
"message": "`expiresAt` field is mandatory.", "message": "`expiresAt` field is mandatory.",
"code": "missing_parameter", "code": "missing_api_key_expires_at",
"type": "invalid_request", "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); assert_eq!(response, expected_response);