From 436ae4e46649ec1b56f0708e1fb6394b5828c68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lecrenier?= Date: Thu, 12 Jan 2023 13:55:53 +0100 Subject: [PATCH] Improve error messages generated by deserr Split Json and Query Parameter error types --- Cargo.lock | 2 +- meilisearch-types/Cargo.toml | 1 + meilisearch-types/src/error.rs | 431 +++++++++++++++++++- meilisearch-types/src/keys.rs | 30 +- meilisearch-types/src/lib.rs | 2 + meilisearch-types/src/settings.rs | 34 +- meilisearch-types/src/tasks.rs | 4 +- meilisearch/Cargo.toml | 1 - meilisearch/src/routes/api_key.rs | 16 +- meilisearch/src/routes/indexes/documents.rs | 33 +- meilisearch/src/routes/indexes/mod.rs | 30 +- meilisearch/src/routes/indexes/search.rs | 50 +-- meilisearch/src/routes/indexes/settings.rs | 26 +- meilisearch/src/routes/mod.rs | 26 +- meilisearch/src/routes/swap_indexes.rs | 9 +- meilisearch/src/routes/tasks.rs | 146 +++---- meilisearch/src/search.rs | 40 +- meilisearch/tests/auth/api_keys.rs | 32 +- meilisearch/tests/common/index.rs | 9 +- meilisearch/tests/common/server.rs | 14 +- meilisearch/tests/search/errors.rs | 58 +-- meilisearch/tests/settings/errors.rs | 44 +- meilisearch/tests/settings/get_settings.rs | 2 +- meilisearch/tests/tasks/errors.rs | 168 ++++---- meilisearch/tests/tasks/mod.rs | 42 +- 25 files changed, 802 insertions(+), 448 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4954ca86..da1ec3011 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2348,7 +2348,6 @@ dependencies = [ "rustls-pemfile", "segment", "serde", - "serde-cs", "serde_json", "serde_urlencoded", "sha-1", @@ -2413,6 +2412,7 @@ dependencies = [ "proptest-derive", "roaring", "serde", + "serde-cs", "serde_json", "tar", "tempfile", diff --git a/meilisearch-types/Cargo.toml b/meilisearch-types/Cargo.toml index bd596ba2d..4c0b1ca93 100644 --- a/meilisearch-types/Cargo.toml +++ b/meilisearch-types/Cargo.toml @@ -21,6 +21,7 @@ proptest = { version = "1.0.0", optional = true } proptest-derive = { version = "0.3.0", optional = true } roaring = { version = "0.10.0", features = ["serde"] } serde = { version = "1.0.145", features = ["derive"] } +serde-cs = "0.2.4" serde_json = "1.0.85" tar = "0.4.38" tempfile = "3.3.0" diff --git a/meilisearch-types/src/error.rs b/meilisearch-types/src/error.rs index bc29f9e82..2be6ffff4 100644 --- a/meilisearch-types/src/error.rs +++ b/meilisearch-types/src/error.rs @@ -1,14 +1,18 @@ use std::convert::Infallible; use std::marker::PhantomData; +use std::str::FromStr; use std::{fmt, io}; use actix_web::http::StatusCode; use actix_web::{self as aweb, HttpResponseBuilder}; use aweb::rt::task::JoinError; use convert_case::Casing; -use deserr::{DeserializeError, IntoValue, MergeWithError, ValuePointerRef}; +use deserr::{DeserializeError, ErrorKind, IntoValue, MergeWithError, ValueKind, ValuePointerRef}; use milli::heed::{Error as HeedError, MdbError}; use serde::{Deserialize, Serialize}; +use serde_cs::vec::CS; + +use crate::star_or::StarOr; use self::deserr_codes::MissingIndexUid; @@ -422,41 +426,49 @@ mod strategy { } } -pub struct DeserrError { +pub struct DeserrJson; +pub struct DeserrQueryParam; + +pub type DeserrJsonError = DeserrError; +pub type DeserrQueryParamError = DeserrError; + +pub struct DeserrError { pub msg: String, pub code: Code, - _phantom: PhantomData, + _phantom: PhantomData<(Format, C)>, } -impl std::fmt::Debug for DeserrError { +impl std::fmt::Debug for DeserrError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeserrError").field("msg", &self.msg).field("code", &self.code).finish() } } -impl std::fmt::Display for DeserrError { +impl std::fmt::Display for DeserrError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.msg) } } -impl std::error::Error for DeserrError {} -impl ErrorCode for DeserrError { +impl std::error::Error for DeserrError {} +impl ErrorCode for DeserrError { fn error_code(&self) -> Code { self.code } } -impl MergeWithError> for DeserrError { +impl + MergeWithError> for DeserrError +{ fn merge( _self_: Option, - other: DeserrError, + other: DeserrError, _merge_location: ValuePointerRef, ) -> Result { Err(DeserrError { msg: other.msg, code: other.code, _phantom: PhantomData }) } } -impl DeserrError { +impl DeserrJsonError { pub fn missing_index_uid(field: &str, location: ValuePointerRef) -> Self { let x = unwrap_any(Self::error::( None, @@ -467,21 +479,364 @@ impl DeserrError { } } -impl deserr::DeserializeError for DeserrError { +// if the error happened in the root, then an empty string is returned. +pub fn location_json_description(location: ValuePointerRef, article: &str) -> String { + fn rec(location: ValuePointerRef) -> String { + match location { + ValuePointerRef::Origin => String::new(), + ValuePointerRef::Key { key, prev } => rec(*prev) + "." + key, + ValuePointerRef::Index { index, prev } => format!("{}[{index}]", rec(*prev)), + } + } + match location { + ValuePointerRef::Origin => String::new(), + _ => { + format!("{article} `{}`", rec(location)) + } + } +} + +fn value_kinds_description_json(kinds: &[ValueKind]) -> String { + fn order(kind: &ValueKind) -> u8 { + match kind { + ValueKind::Null => 0, + ValueKind::Boolean => 1, + ValueKind::Integer => 2, + ValueKind::NegativeInteger => 3, + ValueKind::Float => 4, + ValueKind::String => 5, + ValueKind::Sequence => 6, + ValueKind::Map => 7, + } + } + + fn single_description(kind: &ValueKind) -> &'static str { + match kind { + ValueKind::Null => "null", + ValueKind::Boolean => "a boolean", + ValueKind::Integer => "a positive integer", + ValueKind::NegativeInteger => "an integer", + ValueKind::Float => "a number", + ValueKind::String => "a string", + ValueKind::Sequence => "an array", + ValueKind::Map => "an object", + } + } + + fn description_rec(kinds: &[ValueKind], count_items: &mut usize, message: &mut String) { + let (msg_part, rest): (_, &[ValueKind]) = match kinds { + [] => (String::new(), &[]), + [ValueKind::Integer | ValueKind::NegativeInteger, ValueKind::Float, rest @ ..] => { + ("a number".to_owned(), rest) + } + [ValueKind::Integer, ValueKind::NegativeInteger, ValueKind::Float, rest @ ..] => { + ("a number".to_owned(), rest) + } + [ValueKind::Integer, ValueKind::NegativeInteger, rest @ ..] => { + ("an integer".to_owned(), rest) + } + [a] => (single_description(a).to_owned(), &[]), + [a, rest @ ..] => (single_description(a).to_owned(), rest), + }; + + if rest.is_empty() { + if *count_items == 0 { + message.push_str(&msg_part); + } else if *count_items == 1 { + message.push_str(&format!(" or {msg_part}")); + } else { + message.push_str(&format!(", or {msg_part}")); + } + } else { + if *count_items == 0 { + message.push_str(&msg_part); + } else { + message.push_str(&format!(", {msg_part}")); + } + + *count_items += 1; + description_rec(rest, count_items, message); + } + } + + let mut kinds = kinds.to_owned(); + kinds.sort_by_key(order); + kinds.dedup(); + + if kinds.is_empty() { + "a different value".to_owned() + } else { + let mut message = String::new(); + description_rec(kinds.as_slice(), &mut 0, &mut message); + message + } +} + +fn value_description_with_kind_json(v: &serde_json::Value) -> String { + match v.kind() { + ValueKind::Null => "null".to_owned(), + kind => { + format!( + "{}: `{}`", + value_kinds_description_json(&[kind]), + serde_json::to_string(v).unwrap() + ) + } + } +} + +impl deserr::DeserializeError for DeserrJsonError { fn error( _self_: Option, error: deserr::ErrorKind, location: ValuePointerRef, ) -> Result { - let msg = unwrap_any(deserr::serde_json::JsonError::error(None, error, location)).0; + let mut message = String::new(); - Err(DeserrError { msg, code: C::default().error_code(), _phantom: PhantomData }) + message.push_str(&match error { + ErrorKind::IncorrectValueKind { actual, accepted } => { + let expected = value_kinds_description_json(accepted); + // if we're not able to get the value as a string then we print nothing. + let received = value_description_with_kind_json(&serde_json::Value::from(actual)); + + let location = location_json_description(location, " at"); + + format!("Invalid value type{location}: expected {expected}, but found {received}") + } + ErrorKind::MissingField { field } => { + // serde_json original message: + // Json deserialize error: missing field `lol` at line 1 column 2 + let location = location_json_description(location, " inside"); + format!("Missing field `{field}`{location}") + } + ErrorKind::UnknownKey { key, accepted } => { + let location = location_json_description(location, " inside"); + format!( + "Unknown field `{}`{location}: expected one of {}", + key, + accepted + .iter() + .map(|accepted| format!("`{}`", accepted)) + .collect::>() + .join(", ") + ) + } + ErrorKind::UnknownValue { value, accepted } => { + let location = location_json_description(location, " at"); + format!( + "Unknown value `{}`{location}: expected one of {}", + value, + accepted + .iter() + .map(|accepted| format!("`{}`", accepted)) + .collect::>() + .join(", "), + ) + } + ErrorKind::Unexpected { msg } => { + let location = location_json_description(location, " at"); + // serde_json original message: + // The json payload provided is malformed. `trailing characters at line 1 column 19`. + format!("Invalid value{location}: {msg}") + } + }); + + Err(DeserrJsonError { + msg: message, + code: C::default().error_code(), + _phantom: PhantomData, + }) } } +// if the error happened in the root, then an empty string is returned. +pub fn location_query_param_description(location: ValuePointerRef, article: &str) -> String { + fn rec(location: ValuePointerRef) -> String { + match location { + ValuePointerRef::Origin => String::new(), + ValuePointerRef::Key { key, prev } => { + if matches!(prev, ValuePointerRef::Origin) { + key.to_owned() + } else { + rec(*prev) + "." + key + } + } + ValuePointerRef::Index { index, prev } => format!("{}[{index}]", rec(*prev)), + } + } + match location { + ValuePointerRef::Origin => String::new(), + _ => { + format!("{article} `{}`", rec(location)) + } + } +} + +impl deserr::DeserializeError for DeserrQueryParamError { + fn error( + _self_: Option, + error: deserr::ErrorKind, + location: ValuePointerRef, + ) -> Result { + let mut message = String::new(); + + message.push_str(&match error { + ErrorKind::IncorrectValueKind { actual, accepted } => { + let expected = value_kinds_description_query_param(accepted); + // if we're not able to get the value as a string then we print nothing. + let received = value_description_with_kind_query_param(actual); + + let location = location_query_param_description(location, " for parameter"); + + format!("Invalid value type{location}: expected {expected}, but found {received}") + } + ErrorKind::MissingField { field } => { + // serde_json original message: + // Json deserialize error: missing field `lol` at line 1 column 2 + let location = location_query_param_description(location, " inside"); + format!("Missing parameter `{field}`{location}") + } + ErrorKind::UnknownKey { key, accepted } => { + let location = location_query_param_description(location, " inside"); + format!( + "Unknown parameter `{}`{location}: expected one of {}", + key, + accepted + .iter() + .map(|accepted| format!("`{}`", accepted)) + .collect::>() + .join(", ") + ) + } + ErrorKind::UnknownValue { value, accepted } => { + let location = location_query_param_description(location, " for parameter"); + format!( + "Unknown value `{}`{location}: expected one of {}", + value, + accepted + .iter() + .map(|accepted| format!("`{}`", accepted)) + .collect::>() + .join(", "), + ) + } + ErrorKind::Unexpected { msg } => { + let location = location_query_param_description(location, " in parameter"); + // serde_json original message: + // The json payload provided is malformed. `trailing characters at line 1 column 19`. + format!("Invalid value{location}: {msg}") + } + }); + + Err(DeserrQueryParamError { + msg: message, + code: C::default().error_code(), + _phantom: PhantomData, + }) + } +} + +fn value_kinds_description_query_param(_accepted: &[ValueKind]) -> String { + "a string".to_owned() +} + +fn value_description_with_kind_query_param(actual: deserr::Value) -> String { + match actual { + deserr::Value::Null => "null".to_owned(), + deserr::Value::Boolean(x) => format!("a boolean: `{x}`"), + deserr::Value::Integer(x) => format!("an integer: `{x}`"), + deserr::Value::NegativeInteger(x) => { + format!("an integer: `{x}`") + } + deserr::Value::Float(x) => { + format!("a number: `{x}`") + } + deserr::Value::String(x) => { + format!("a string: `{x}`") + } + deserr::Value::Sequence(_) => "multiple values".to_owned(), + deserr::Value::Map(_) => "multiple parameters".to_owned(), + } +} + +#[derive(Debug)] +pub struct DetailedParseIntError(String); +impl fmt::Display for DetailedParseIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "could not parse `{}` as a positive integer", self.0) + } +} +impl std::error::Error for DetailedParseIntError {} + +pub fn parse_u32_query_param(x: String) -> Result> { + x.parse::().map_err(|_e| TakeErrorMessage(DetailedParseIntError(x.to_owned()))) +} +pub fn parse_usize_query_param( + x: String, +) -> Result> { + x.parse::().map_err(|_e| TakeErrorMessage(DetailedParseIntError(x.to_owned()))) +} +pub fn parse_option_usize_query_param( + s: Option, +) -> Result, TakeErrorMessage> { + if let Some(s) = s { + parse_usize_query_param(s).map(Some) + } else { + Ok(None) + } +} +pub fn parse_option_u32_query_param( + s: Option, +) -> Result, TakeErrorMessage> { + if let Some(s) = s { + parse_u32_query_param(s).map(Some) + } else { + Ok(None) + } +} +pub fn parse_option_vec_u32_query_param( + s: Option>, +) -> Result>, TakeErrorMessage> { + if let Some(s) = s { + s.into_iter() + .map(parse_u32_query_param) + .collect::, TakeErrorMessage>>() + .map(Some) + } else { + Ok(None) + } +} +pub fn parse_option_cs_star_or( + s: Option>>, +) -> Result>, TakeErrorMessage> { + if let Some(s) = s.and_then(fold_star_or) as Option> { + s.into_iter() + .map(|s| T::from_str(&s)) + .collect::, T::Err>>() + .map_err(TakeErrorMessage) + .map(Some) + } else { + Ok(None) + } +} + +/// Extracts the raw values from the `StarOr` types and +/// return None if a `StarOr::Star` is encountered. +pub fn fold_star_or(content: impl IntoIterator>) -> Option +where + O: FromIterator, +{ + content + .into_iter() + .map(|value| match value { + StarOr::Star => None, + StarOr::Other(val) => Some(val), + }) + .collect() +} pub struct TakeErrorMessage(pub T); -impl MergeWithError> for DeserrError +impl MergeWithError> for DeserrJsonError where T: std::error::Error, { @@ -490,7 +845,24 @@ where other: TakeErrorMessage, merge_location: ValuePointerRef, ) -> Result { - DeserrError::error::( + DeserrJsonError::error::( + None, + deserr::ErrorKind::Unexpected { msg: other.0.to_string() }, + merge_location, + ) + } +} + +impl MergeWithError> for DeserrQueryParamError +where + T: std::error::Error, +{ + fn merge( + _self_: Option, + other: TakeErrorMessage, + merge_location: ValuePointerRef, + ) -> Result { + DeserrQueryParamError::error::( None, deserr::ErrorKind::Unexpected { msg: other.0.to_string() }, merge_location, @@ -510,3 +882,32 @@ macro_rules! internal_error { )* } } + +#[cfg(test)] +mod tests { + use deserr::ValueKind; + + use crate::error::value_kinds_description_json; + + #[test] + fn test_value_kinds_description_json() { + insta::assert_display_snapshot!(value_kinds_description_json(&[]), @"a different value"); + + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Boolean]), @"a boolean"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer]), @"a positive integer"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::NegativeInteger]), @"an integer"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer]), @"a positive integer"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::String]), @"a string"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Sequence]), @"an array"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Map]), @"an object"); + + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer, ValueKind::Boolean]), @"a boolean or a positive integer"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Null, ValueKind::Integer]), @"null or a positive integer"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Sequence, ValueKind::NegativeInteger]), @"an integer or an array"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer, ValueKind::Float]), @"a number"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer, ValueKind::Float, ValueKind::NegativeInteger]), @"a number"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Integer, ValueKind::Float, ValueKind::NegativeInteger, ValueKind::Null]), @"null or a number"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Boolean, ValueKind::Integer, ValueKind::Float, ValueKind::NegativeInteger, ValueKind::Null]), @"null, a boolean, or a number"); + insta::assert_display_snapshot!(value_kinds_description_json(&[ValueKind::Null, ValueKind::Boolean, ValueKind::Integer, ValueKind::Float, ValueKind::NegativeInteger, ValueKind::Null]), @"null, a boolean, or a number"); + } +} diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index b41bb06b6..53776e489 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -11,19 +11,19 @@ use time::{Date, OffsetDateTime, PrimitiveDateTime}; use uuid::Uuid; use crate::error::deserr_codes::*; -use crate::error::{unwrap_any, Code, DeserrError, ErrorCode, TakeErrorMessage}; +use crate::error::{unwrap_any, Code, DeserrJsonError, ErrorCode, TakeErrorMessage}; use crate::index_uid::{IndexUid, IndexUidFormatError}; use crate::star_or::StarOr; pub type KeyId = Uuid; -impl MergeWithError for DeserrError { +impl MergeWithError for DeserrJsonError { fn merge( _self_: Option, other: IndexUidFormatError, merge_location: deserr::ValuePointerRef, ) -> std::result::Result { - DeserrError::error::( + DeserrJsonError::error::( None, deserr::ErrorKind::Unexpected { msg: other.to_string() }, merge_location, @@ -36,19 +36,19 @@ fn parse_uuid_from_str(s: &str) -> Result> { } #[derive(Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct CreateApiKey { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub description: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub name: Option, - #[deserr(default = Uuid::new_v4(), error = DeserrError, from(&String) = parse_uuid_from_str -> TakeErrorMessage)] + #[deserr(default = Uuid::new_v4(), error = DeserrJsonError, from(&String) = parse_uuid_from_str -> TakeErrorMessage)] pub uid: KeyId, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub actions: Vec, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub indexes: Vec>, - #[deserr(error = DeserrError, default = None, from(&String) = parse_expiration_date -> TakeErrorMessage)] + #[deserr(error = DeserrJsonError, default = None, from(&String) = parse_expiration_date -> TakeErrorMessage)] pub expires_at: Option, } impl CreateApiKey { @@ -72,8 +72,8 @@ fn deny_immutable_fields_api_key( field: &str, accepted: &[&str], location: ValuePointerRef, -) -> DeserrError { - let mut error = unwrap_any(DeserrError::::error::( +) -> DeserrJsonError { + let mut error = unwrap_any(DeserrJsonError::::error::( None, deserr::ErrorKind::UnknownKey { key: field, accepted }, location, @@ -92,11 +92,11 @@ fn deny_immutable_fields_api_key( } #[derive(Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_api_key)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_api_key)] pub struct PatchApiKey { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub description: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub name: Option, } diff --git a/meilisearch-types/src/lib.rs b/meilisearch-types/src/lib.rs index c7f7ca7f5..f8fc47abd 100644 --- a/meilisearch-types/src/lib.rs +++ b/meilisearch-types/src/lib.rs @@ -8,8 +8,10 @@ pub mod star_or; pub mod tasks; pub mod versioning; +pub use deserr; pub use milli; pub use milli::{heed, Index}; +pub use serde_cs; use uuid::Uuid; pub use versioning::VERSION_FILE_NAME; diff --git a/meilisearch-types/src/settings.rs b/meilisearch-types/src/settings.rs index 3169920a6..0a79f865e 100644 --- a/meilisearch-types/src/settings.rs +++ b/meilisearch-types/src/settings.rs @@ -12,7 +12,7 @@ use milli::{Criterion, CriterionError, Index, DEFAULT_VALUES_PER_FACET}; use serde::{Deserialize, Serialize, Serializer}; use crate::error::deserr_codes::*; -use crate::error::{unwrap_any, DeserrError}; +use crate::error::{unwrap_any, DeserrJsonError}; /// The maximimum number of results that the engine /// will be able to return in one search call. @@ -66,7 +66,7 @@ fn validate_min_word_size_for_typo_setting( #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, DeserializeFromValue)] #[serde(deny_unknown_fields, rename_all = "camelCase")] -#[deserr(deny_unknown_fields, rename_all = camelCase, validate = validate_min_word_size_for_typo_setting -> DeserrError)] +#[deserr(deny_unknown_fields, rename_all = camelCase, validate = validate_min_word_size_for_typo_setting -> DeserrJsonError)] pub struct MinWordSizeTyposSetting { #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub one_typo: Setting, @@ -76,12 +76,12 @@ pub struct MinWordSizeTyposSetting { #[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq, DeserializeFromValue)] #[serde(deny_unknown_fields, rename_all = "camelCase")] -#[deserr(deny_unknown_fields, rename_all = camelCase, where_predicate = __Deserr_E: deserr::MergeWithError>)] +#[deserr(deny_unknown_fields, rename_all = camelCase, where_predicate = __Deserr_E: deserr::MergeWithError>)] pub struct TypoSettings { #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub enabled: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub min_word_size_for_typos: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub disable_on_words: Setting>, @@ -105,7 +105,7 @@ pub struct PaginationSettings { pub max_total_hits: Setting, } -impl MergeWithError for DeserrError { +impl MergeWithError for DeserrJsonError { fn merge( _self_: Option, other: milli::CriterionError, @@ -128,14 +128,14 @@ impl MergeWithError for DeserrError { #[serde( default, serialize_with = "serialize_with_wildcard", skip_serializing_if = "Setting::is_not_set" )] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub displayed_attributes: Setting>, #[serde( @@ -143,35 +143,35 @@ pub struct Settings { serialize_with = "serialize_with_wildcard", skip_serializing_if = "Setting::is_not_set" )] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub searchable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub filterable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub sortable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub ranking_rules: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub stop_words: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub synonyms: Setting>>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub distinct_attribute: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub typo_tolerance: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub faceting: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub pagination: Setting, #[serde(skip)] diff --git a/meilisearch-types/src/tasks.rs b/meilisearch-types/src/tasks.rs index ceddbd51c..fd2d31e06 100644 --- a/meilisearch-types/src/tasks.rs +++ b/meilisearch-types/src/tasks.rs @@ -348,7 +348,7 @@ impl FromStr for Status { } else { Err(ResponseError::from_msg( format!( - "`{}` is not a status. Available status are {}.", + "`{}` is not a valid task status. Available statuses are {}.", status, enum_iterator::all::() .map(|s| format!("`{s}`")) @@ -440,7 +440,7 @@ impl FromStr for Kind { } else { Err(ResponseError::from_msg( format!( - "`{}` is not a type. Available types are {}.", + "`{}` is not a valid task type. Available types are {}.", kind, enum_iterator::all::() .map(|k| format!( diff --git a/meilisearch/Cargo.toml b/meilisearch/Cargo.toml index a42e5cc7b..be852c02e 100644 --- a/meilisearch/Cargo.toml +++ b/meilisearch/Cargo.toml @@ -55,7 +55,6 @@ rustls = "0.20.6" rustls-pemfile = "1.0.1" segment = { version = "0.2.1", optional = true } serde = { version = "1.0.145", features = ["derive"] } -serde-cs = "0.2.4" serde_json = { version = "1.0.85", features = ["preserve_order"] } sha2 = "0.10.6" siphasher = "0.3.10" diff --git a/meilisearch/src/routes/api_key.rs b/meilisearch/src/routes/api_key.rs index 76912bbaa..ce4ab0696 100644 --- a/meilisearch/src/routes/api_key.rs +++ b/meilisearch/src/routes/api_key.rs @@ -4,8 +4,8 @@ use actix_web::{web, HttpRequest, HttpResponse}; use deserr::DeserializeFromValue; use meilisearch_auth::error::AuthControllerError; use meilisearch_auth::AuthController; -use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::{Code, DeserrError, ResponseError, TakeErrorMessage}; +use meilisearch_types::error::{deserr_codes::*, DeserrQueryParamError}; +use meilisearch_types::error::{Code, DeserrJsonError, ResponseError, TakeErrorMessage}; use meilisearch_types::keys::{Action, CreateApiKey, Key, PatchApiKey}; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; @@ -36,7 +36,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { pub async fn create_api_key( auth_controller: GuardedData, AuthController>, - body: ValidatedJson, + body: ValidatedJson, _req: HttpRequest, ) -> Result { let v = body.into_inner(); @@ -51,14 +51,14 @@ pub async fn create_api_key( } #[derive(DeserializeFromValue, Deserialize, Debug, Clone, Copy)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ListApiKeys { #[serde(default)] - #[deserr(error = DeserrError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] pub offset: usize, #[serde(default = "PAGINATION_DEFAULT_LIMIT")] - #[deserr(error = DeserrError, default = PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] pub limit: usize, } impl ListApiKeys { @@ -69,7 +69,7 @@ impl ListApiKeys { pub async fn list_api_keys( auth_controller: GuardedData, AuthController>, - list_api_keys: QueryParameter, + list_api_keys: QueryParameter, ) -> Result { let paginate = list_api_keys.into_inner().as_pagination(); let page_view = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> { @@ -106,7 +106,7 @@ pub async fn get_api_key( pub async fn patch_api_key( auth_controller: GuardedData, AuthController>, - body: ValidatedJson, + body: ValidatedJson, path: web::Path, ) -> Result { let key = path.into_inner().key; diff --git a/meilisearch/src/routes/indexes/documents.rs b/meilisearch/src/routes/indexes/documents.rs index 3a54bba6a..c09b12244 100644 --- a/meilisearch/src/routes/indexes/documents.rs +++ b/meilisearch/src/routes/indexes/documents.rs @@ -10,18 +10,18 @@ use futures::StreamExt; use index_scheduler::IndexScheduler; use log::debug; use meilisearch_types::document_formats::{read_csv, read_json, read_ndjson, PayloadType}; -use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::{DeserrError, ResponseError, TakeErrorMessage}; +use meilisearch_types::error::{deserr_codes::*, fold_star_or, DeserrQueryParamError}; +use meilisearch_types::error::{DeserrJsonError, ResponseError, TakeErrorMessage}; use meilisearch_types::heed::RoTxn; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::milli::update::IndexDocumentsMethod; +use meilisearch_types::serde_cs::vec::CS; use meilisearch_types::star_or::StarOr; use meilisearch_types::tasks::KindWithContent; use meilisearch_types::{milli, Document, Index}; use mime::Mime; use once_cell::sync::Lazy; use serde::Deserialize; -use serde_cs::vec::CS; use serde_json::Value; use tempfile::tempfile; use tokio::fs::File; @@ -36,7 +36,7 @@ use crate::extractors::authentication::GuardedData; use crate::extractors::payload::Payload; use crate::extractors::query_parameters::QueryParameter; use crate::extractors::sequential_extractor::SeqHandler; -use crate::routes::{fold_star_or, PaginationView, SummarizedTaskView}; +use crate::routes::{PaginationView, SummarizedTaskView}; static ACCEPTED_CONTENT_TYPE: Lazy> = Lazy::new(|| { vec!["application/json".to_string(), "application/x-ndjson".to_string(), "text/csv".to_string()] @@ -82,16 +82,17 @@ pub fn configure(cfg: &mut web::ServiceConfig) { } #[derive(Deserialize, Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] pub struct GetDocument { - #[deserr(error = DeserrError)] + // TODO: strongly typed argument here + #[deserr(error = DeserrQueryParamError)] fields: Option>>, } pub async fn get_document( index_scheduler: GuardedData, Data>, path: web::Path, - params: QueryParameter, + params: QueryParameter, ) -> Result { let GetDocument { fields } = params.into_inner(); let attributes_to_retrieve = fields.and_then(fold_star_or); @@ -119,20 +120,20 @@ pub async fn delete_document( } #[derive(Deserialize, Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] pub struct BrowseQuery { - #[deserr(error = DeserrError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] offset: usize, - #[deserr(error = DeserrError, default = crate::routes::PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = crate::routes::PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] limit: usize, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] fields: Option>>, } pub async fn get_all_documents( index_scheduler: GuardedData, Data>, index_uid: web::Path, - params: QueryParameter, + params: QueryParameter, ) -> Result { debug!("called with params: {:?}", params); let BrowseQuery { limit, offset, fields } = params.into_inner(); @@ -148,16 +149,16 @@ pub async fn get_all_documents( } #[derive(Deserialize, Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct UpdateDocumentsQuery { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub primary_key: Option, } pub async fn add_documents( index_scheduler: GuardedData, Data>, index_uid: web::Path, - params: QueryParameter, + params: QueryParameter, body: Payload, req: HttpRequest, analytics: web::Data, @@ -185,7 +186,7 @@ pub async fn add_documents( pub async fn update_documents( index_scheduler: GuardedData, Data>, path: web::Path, - params: QueryParameter, + params: QueryParameter, body: Payload, req: HttpRequest, analytics: web::Data, diff --git a/meilisearch/src/routes/indexes/mod.rs b/meilisearch/src/routes/indexes/mod.rs index 7a3a97c1f..061eefaf6 100644 --- a/meilisearch/src/routes/indexes/mod.rs +++ b/meilisearch/src/routes/indexes/mod.rs @@ -5,8 +5,8 @@ use actix_web::{web, HttpRequest, HttpResponse}; use deserr::{DeserializeError, DeserializeFromValue, ValuePointerRef}; use index_scheduler::IndexScheduler; use log::debug; -use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::{unwrap_any, Code, DeserrError, ResponseError, TakeErrorMessage}; +use meilisearch_types::error::{deserr_codes::*, unwrap_any, Code, DeserrQueryParamError}; +use meilisearch_types::error::{DeserrJsonError, ResponseError, TakeErrorMessage}; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::milli::{self, FieldDistribution, Index}; use meilisearch_types::tasks::KindWithContent; @@ -72,14 +72,14 @@ impl IndexView { } #[derive(DeserializeFromValue, Deserialize, Debug, Clone, Copy)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ListIndexes { #[serde(default)] - #[deserr(error = DeserrError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default, from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] pub offset: usize, #[serde(default = "PAGINATION_DEFAULT_LIMIT")] - #[deserr(error = DeserrError, default = PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = PAGINATION_DEFAULT_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] pub limit: usize, } impl ListIndexes { @@ -90,7 +90,7 @@ impl ListIndexes { pub async fn list_indexes( index_scheduler: GuardedData, Data>, - paginate: QueryParameter, + paginate: QueryParameter, ) -> Result { let search_rules = &index_scheduler.filters().search_rules; let indexes: Vec<_> = index_scheduler.indexes()?; @@ -107,17 +107,17 @@ pub async fn list_indexes( } #[derive(DeserializeFromValue, Debug)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct IndexCreateRequest { - #[deserr(error = DeserrError, missing_field_error = DeserrError::missing_index_uid)] + #[deserr(error = DeserrJsonError, missing_field_error = DeserrJsonError::missing_index_uid)] uid: String, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] primary_key: Option, } pub async fn create_index( index_scheduler: GuardedData, Data>, - body: ValidatedJson, + body: ValidatedJson, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -146,8 +146,8 @@ fn deny_immutable_fields_index( field: &str, accepted: &[&str], location: ValuePointerRef, -) -> DeserrError { - let mut error = unwrap_any(DeserrError::::error::( +) -> DeserrJsonError { + let mut error = unwrap_any(DeserrJsonError::::error::( None, deserr::ErrorKind::UnknownKey { key: field, accepted }, location, @@ -162,9 +162,9 @@ fn deny_immutable_fields_index( error } #[derive(DeserializeFromValue, Debug)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_index)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_index)] pub struct UpdateIndexRequest { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] primary_key: Option, } @@ -183,7 +183,7 @@ pub async fn get_index( pub async fn update_index( index_scheduler: GuardedData, Data>, path: web::Path, - body: ValidatedJson, + body: ValidatedJson, req: HttpRequest, analytics: web::Data, ) -> Result { diff --git a/meilisearch/src/routes/indexes/search.rs b/meilisearch/src/routes/indexes/search.rs index 6296772e0..8819ac8cf 100644 --- a/meilisearch/src/routes/indexes/search.rs +++ b/meilisearch/src/routes/indexes/search.rs @@ -5,9 +5,12 @@ use actix_web::{web, HttpRequest, HttpResponse}; use index_scheduler::IndexScheduler; use log::debug; use meilisearch_auth::IndexSearchRules; -use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::{DeserrError, ResponseError, TakeErrorMessage}; -use serde_cs::vec::CS; +use meilisearch_types::error::{ + deserr_codes::*, parse_option_usize_query_param, parse_usize_query_param, + DeserrQueryParamError, DetailedParseIntError, +}; +use meilisearch_types::error::{DeserrJsonError, ResponseError, TakeErrorMessage}; +use meilisearch_types::serde_cs::vec::CS; use serde_json::Value; use crate::analytics::{Analytics, SearchAggregator}; @@ -16,7 +19,6 @@ use crate::extractors::authentication::GuardedData; use crate::extractors::json::ValidatedJson; use crate::extractors::query_parameters::QueryParameter; use crate::extractors::sequential_extractor::SeqHandler; -use crate::routes::from_string_to_option_take_error_message; use crate::search::{ perform_search, MatchingStrategy, SearchQuery, DEFAULT_CROP_LENGTH, DEFAULT_CROP_MARKER, DEFAULT_HIGHLIGHT_POST_TAG, DEFAULT_HIGHLIGHT_PRE_TAG, DEFAULT_SEARCH_LIMIT, @@ -44,41 +46,41 @@ pub fn parse_bool_take_error_message( } #[derive(Debug, deserr::DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] pub struct SearchQueryGet { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] q: Option, - #[deserr(error = DeserrError, default = DEFAULT_SEARCH_OFFSET(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_SEARCH_OFFSET(), from(String) = parse_usize_query_param -> TakeErrorMessage)] offset: usize, - #[deserr(error = DeserrError, default = DEFAULT_SEARCH_LIMIT(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_SEARCH_LIMIT(), from(String) = parse_usize_query_param -> TakeErrorMessage)] limit: usize, - #[deserr(error = DeserrError, from(&String) = from_string_to_option_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option) = parse_option_usize_query_param -> TakeErrorMessage)] page: Option, - #[deserr(error = DeserrError, from(&String) = from_string_to_option_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option) = parse_option_usize_query_param -> TakeErrorMessage)] hits_per_page: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] attributes_to_retrieve: Option>, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] attributes_to_crop: Option>, - #[deserr(error = DeserrError, default = DEFAULT_CROP_LENGTH(), from(&String) = parse_usize_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_CROP_LENGTH(), from(String) = parse_usize_query_param -> TakeErrorMessage)] crop_length: usize, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] attributes_to_highlight: Option>, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] filter: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] sort: Option, - #[deserr(error = DeserrError, default, from(&String) = parse_bool_take_error_message -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default, from(&String) = parse_bool_take_error_message -> TakeErrorMessage)] show_matches_position: bool, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrQueryParamError)] facets: Option>, - #[deserr(error = DeserrError, default = DEFAULT_HIGHLIGHT_PRE_TAG())] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_HIGHLIGHT_PRE_TAG())] highlight_pre_tag: String, - #[deserr(error = DeserrError, default = DEFAULT_HIGHLIGHT_POST_TAG())] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_HIGHLIGHT_POST_TAG())] highlight_post_tag: String, - #[deserr(error = DeserrError, default = DEFAULT_CROP_MARKER())] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_CROP_MARKER())] crop_marker: String, - #[deserr(error = DeserrError, default)] + #[deserr(error = DeserrQueryParamError, default)] matching_strategy: MatchingStrategy, } @@ -162,7 +164,7 @@ fn fix_sort_query_parameters(sort_query: &str) -> Vec { pub async fn search_with_url_query( index_scheduler: GuardedData, Data>, index_uid: web::Path, - params: QueryParameter, + params: QueryParameter, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -194,7 +196,7 @@ pub async fn search_with_url_query( pub async fn search_with_post( index_scheduler: GuardedData, Data>, index_uid: web::Path, - params: ValidatedJson, + params: ValidatedJson, req: HttpRequest, analytics: web::Data, ) -> Result { diff --git a/meilisearch/src/routes/indexes/settings.rs b/meilisearch/src/routes/indexes/settings.rs index 13c280d63..404835833 100644 --- a/meilisearch/src/routes/indexes/settings.rs +++ b/meilisearch/src/routes/indexes/settings.rs @@ -2,7 +2,7 @@ use actix_web::web::Data; use actix_web::{web, HttpRequest, HttpResponse}; use index_scheduler::IndexScheduler; use log::debug; -use meilisearch_types::error::{DeserrError, ResponseError}; +use meilisearch_types::error::{DeserrJsonError, ResponseError}; use meilisearch_types::index_uid::IndexUid; use meilisearch_types::settings::{settings, RankingRuleView, Settings, Unchecked}; use meilisearch_types::tasks::KindWithContent; @@ -130,7 +130,7 @@ make_setting_route!( "/filterable-attributes", put, std::collections::BTreeSet, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsFilterableAttributes, >, filterable_attributes, @@ -156,7 +156,7 @@ make_setting_route!( "/sortable-attributes", put, std::collections::BTreeSet, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSortableAttributes, >, sortable_attributes, @@ -182,7 +182,7 @@ make_setting_route!( "/displayed-attributes", put, Vec, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsDisplayedAttributes, >, displayed_attributes, @@ -208,7 +208,7 @@ make_setting_route!( "/typo-tolerance", patch, meilisearch_types::settings::TypoSettings, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsTypoTolerance, >, typo_tolerance, @@ -253,7 +253,7 @@ make_setting_route!( "/searchable-attributes", put, Vec, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSearchableAttributes, >, searchable_attributes, @@ -279,7 +279,7 @@ make_setting_route!( "/stop-words", put, std::collections::BTreeSet, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsStopWords, >, stop_words, @@ -304,7 +304,7 @@ make_setting_route!( "/synonyms", put, std::collections::BTreeMap>, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsSynonyms, >, synonyms, @@ -329,7 +329,7 @@ make_setting_route!( "/distinct-attribute", put, String, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsDistinctAttribute, >, distinct_attribute, @@ -353,7 +353,7 @@ make_setting_route!( "/ranking-rules", put, Vec, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsRankingRules, >, ranking_rules, @@ -384,7 +384,7 @@ make_setting_route!( "/faceting", patch, meilisearch_types::settings::FacetingSettings, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsFaceting, >, faceting, @@ -409,7 +409,7 @@ make_setting_route!( "/pagination", patch, meilisearch_types::settings::PaginationSettings, - meilisearch_types::error::DeserrError< + meilisearch_types::error::DeserrJsonError< meilisearch_types::error::deserr_codes::InvalidSettingsPagination, >, pagination, @@ -461,7 +461,7 @@ generate_configure!( pub async fn update_all( index_scheduler: GuardedData, Data>, index_uid: web::Path, - body: ValidatedJson, DeserrError>, + body: ValidatedJson, DeserrJsonError>, req: HttpRequest, analytics: web::Data, ) -> Result { diff --git a/meilisearch/src/routes/mod.rs b/meilisearch/src/routes/mod.rs index 2e619540a..e681910a2 100644 --- a/meilisearch/src/routes/mod.rs +++ b/meilisearch/src/routes/mod.rs @@ -5,9 +5,8 @@ use actix_web::web::Data; use actix_web::{web, HttpRequest, HttpResponse}; use index_scheduler::{IndexScheduler, Query}; use log::debug; -use meilisearch_types::error::{ResponseError, TakeErrorMessage}; +use meilisearch_types::error::ResponseError; use meilisearch_types::settings::{Settings, Unchecked}; -use meilisearch_types::star_or::StarOr; use meilisearch_types::tasks::{Kind, Status, Task, TaskId}; use serde::{Deserialize, Serialize}; use serde_json::json; @@ -35,35 +34,12 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(web::scope("/swap-indexes").configure(swap_indexes::configure)); } -/// Extracts the raw values from the `StarOr` types and -/// return None if a `StarOr::Star` is encountered. -pub fn fold_star_or(content: impl IntoIterator>) -> Option -where - O: FromIterator, -{ - content - .into_iter() - .map(|value| match value { - StarOr::Star => None, - StarOr::Other(val) => Some(val), - }) - .collect() -} - pub fn from_string_to_option(input: &str) -> Result, E> where T: FromStr, { Ok(Some(input.parse()?)) } -pub fn from_string_to_option_take_error_message( - input: &str, -) -> Result, TakeErrorMessage> -where - T: FromStr, -{ - Ok(Some(input.parse().map_err(TakeErrorMessage)?)) -} const PAGINATION_DEFAULT_LIMIT: fn() -> usize = || 20; diff --git a/meilisearch/src/routes/swap_indexes.rs b/meilisearch/src/routes/swap_indexes.rs index c5b371cd9..57015f1f1 100644 --- a/meilisearch/src/routes/swap_indexes.rs +++ b/meilisearch/src/routes/swap_indexes.rs @@ -3,7 +3,7 @@ use actix_web::{web, HttpRequest, HttpResponse}; use deserr::DeserializeFromValue; use index_scheduler::IndexScheduler; use meilisearch_types::error::deserr_codes::InvalidSwapIndexes; -use meilisearch_types::error::{DeserrError, ResponseError}; +use meilisearch_types::error::{DeserrJsonError, ResponseError}; use meilisearch_types::tasks::{IndexSwap, KindWithContent}; use serde_json::json; @@ -20,15 +20,15 @@ pub fn configure(cfg: &mut web::ServiceConfig) { } #[derive(DeserializeFromValue, Debug, Clone, PartialEq, Eq)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct SwapIndexesPayload { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] indexes: Vec, } pub async fn swap_indexes( index_scheduler: GuardedData, Data>, - params: ValidatedJson, DeserrError>, + params: ValidatedJson, DeserrJsonError>, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -44,6 +44,7 @@ pub async fn swap_indexes( let mut swaps = vec![]; for SwapIndexesPayload { indexes } in params.into_iter() { + // TODO: switch to deserr let (lhs, rhs) = match indexes.as_slice() { [lhs, rhs] => (lhs, rhs), _ => { diff --git a/meilisearch/src/routes/tasks.rs b/meilisearch/src/routes/tasks.rs index 09723623f..dbf1380e2 100644 --- a/meilisearch/src/routes/tasks.rs +++ b/meilisearch/src/routes/tasks.rs @@ -1,13 +1,15 @@ -use std::num::ParseIntError; -use std::str::FromStr; - use actix_web::web::Data; use actix_web::{web, HttpRequest, HttpResponse}; use deserr::DeserializeFromValue; use index_scheduler::{IndexScheduler, Query, TaskId}; -use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::{DeserrError, ResponseError, TakeErrorMessage}; +use meilisearch_types::error::{ + deserr_codes::*, parse_option_cs_star_or, parse_option_u32_query_param, + parse_option_vec_u32_query_param, DeserrQueryParamError, DetailedParseIntError, + TakeErrorMessage, +}; +use meilisearch_types::error::{parse_u32_query_param, ResponseError}; use meilisearch_types::index_uid::IndexUid; +use meilisearch_types::serde_cs; use meilisearch_types::settings::{Settings, Unchecked}; use meilisearch_types::star_or::StarOr; use meilisearch_types::tasks::{ @@ -21,7 +23,7 @@ use time::macros::format_description; use time::{Date, Duration, OffsetDateTime, Time}; use tokio::task; -use super::{fold_star_or, SummarizedTaskView}; +use super::SummarizedTaskView; use crate::analytics::Analytics; use crate::extractors::authentication::policies::*; use crate::extractors::authentication::GuardedData; @@ -164,108 +166,70 @@ impl From
for DetailsView { } } -fn parse_option_cs( - s: Option>, -) -> Result>, TakeErrorMessage> { - if let Some(s) = s { - s.into_iter() - .map(|s| T::from_str(&s)) - .collect::, T::Err>>() - .map_err(TakeErrorMessage) - .map(Some) - } else { - Ok(None) - } -} -fn parse_option_cs_star_or( - s: Option>>, -) -> Result>, TakeErrorMessage> { - if let Some(s) = s.and_then(fold_star_or) as Option> { - s.into_iter() - .map(|s| T::from_str(&s)) - .collect::, T::Err>>() - .map_err(TakeErrorMessage) - .map(Some) - } else { - Ok(None) - } -} -fn parse_option_str(s: Option) -> Result, TakeErrorMessage> { - if let Some(s) = s { - T::from_str(&s).map_err(TakeErrorMessage).map(Some) - } else { - Ok(None) - } -} - -fn parse_str(s: String) -> Result> { - T::from_str(&s).map_err(TakeErrorMessage) -} - #[derive(Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] pub struct TasksFilterQuery { - #[deserr(error = DeserrError, default = DEFAULT_LIMIT(), from(String) = parse_str:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = DEFAULT_LIMIT(), from(String) = parse_u32_query_param -> TakeErrorMessage)] pub limit: u32, - #[deserr(error = DeserrError, from(Option) = parse_option_str:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option) = parse_option_u32_query_param -> TakeErrorMessage)] pub from: Option, - #[deserr(error = DeserrError, from(Option>) = parse_option_cs:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option>) = parse_option_vec_u32_query_param -> TakeErrorMessage)] pub uids: Option>, - #[deserr(error = DeserrError, from(Option>) = parse_option_cs:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option>) = parse_option_vec_u32_query_param -> TakeErrorMessage)] pub canceled_by: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub types: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub statuses: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub index_uids: Option>, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_enqueued_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_enqueued_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_started_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_started_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_finished_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_finished_at: Option, } #[derive(Deserialize, Debug, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] pub struct TaskDeletionOrCancelationQuery { - #[deserr(error = DeserrError, from(Option>) = parse_option_cs:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option>) = parse_option_vec_u32_query_param -> TakeErrorMessage)] pub uids: Option>, - #[deserr(error = DeserrError, from(Option>) = parse_option_cs:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, from(Option>) = parse_option_vec_u32_query_param -> TakeErrorMessage)] pub canceled_by: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub types: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub statuses: Option>, - #[deserr(error = DeserrError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option>>) = parse_option_cs_star_or:: -> TakeErrorMessage)] pub index_uids: Option>, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_enqueued_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_enqueued_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_started_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_started_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_after -> TakeErrorMessage)] pub after_finished_at: Option, - #[deserr(error = DeserrError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] + #[deserr(error = DeserrQueryParamError, default = None, from(Option) = deserialize_date_before -> TakeErrorMessage)] pub before_finished_at: Option, } async fn cancel_tasks( index_scheduler: GuardedData, Data>, - params: QueryParameter, + params: QueryParameter, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -337,7 +301,7 @@ async fn cancel_tasks( async fn delete_tasks( index_scheduler: GuardedData, Data>, - params: QueryParameter, + params: QueryParameter, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -418,7 +382,7 @@ pub struct AllTasks { async fn get_tasks( index_scheduler: GuardedData, Data>, - params: QueryParameter, + params: QueryParameter, req: HttpRequest, analytics: web::Data, ) -> Result { @@ -584,16 +548,16 @@ impl std::error::Error for InvalidTaskDateError {} mod tests { use deserr::DeserializeFromValue; use meili_snap::snapshot; - use meilisearch_types::error::DeserrError; + use meilisearch_types::error::DeserrQueryParamError; use crate::extractors::query_parameters::QueryParameter; use crate::routes::tasks::{TaskDeletionOrCancelationQuery, TasksFilterQuery}; fn deserr_query_params(j: &str) -> Result where - T: DeserializeFromValue, + T: DeserializeFromValue, { - QueryParameter::::from_query(j).map(|p| p.0) + QueryParameter::::from_query(j).map(|p| p.0) } #[test] @@ -634,33 +598,33 @@ mod tests { { let params = "afterFinishedAt=2021"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterFinishedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `afterFinishedAt`: `2021` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } { let params = "beforeFinishedAt=2021"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeFinishedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `beforeFinishedAt`: `2021` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } { let params = "afterEnqueuedAt=2021-12"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021-12` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterEnqueuedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `afterEnqueuedAt`: `2021-12` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } { let params = "beforeEnqueuedAt=2021-12-03T23"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021-12-03T23` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeEnqueuedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `beforeEnqueuedAt`: `2021-12-03T23` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } { let params = "afterStartedAt=2021-12-03T23:45"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021-12-03T23:45` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterStartedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `afterStartedAt`: `2021-12-03T23:45` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } { let params = "beforeStartedAt=2021-12-03T23:45"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`2021-12-03T23:45` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeStartedAt`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `beforeStartedAt`: `2021-12-03T23:45` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format."); } } @@ -679,12 +643,12 @@ mod tests { { let params = "uids=78,hello,world"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"invalid digit found in string at `.uids`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `uids`: could not parse `hello` as a positive integer"); } { let params = "uids=cat"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"invalid digit found in string at `.uids`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `uids`: could not parse `cat` as a positive integer"); } } @@ -703,7 +667,7 @@ mod tests { { let params = "statuses=finished"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`finished` is not a status. Available status are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`. at `.statuses`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `statuses`: `finished` is not a valid task status. Available statuses are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`."); } } #[test] @@ -721,7 +685,7 @@ mod tests { { let params = "types=createIndex"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`createIndex` is not a type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`. at `.types`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `types`: `createIndex` is not a valid task type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`."); } } #[test] @@ -739,12 +703,12 @@ mod tests { { let params = "indexUids=1,hé"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexUids`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `indexUids`: `hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_)."); } { let params = "indexUids=hé"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"`hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexUids`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `indexUids`: `hé` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_)."); } } @@ -772,19 +736,19 @@ mod tests { // Stars in uids not allowed let params = "uids=*"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"invalid digit found in string at `.uids`."); + snapshot!(format!("{err}"), @"Invalid value in parameter `uids`: could not parse `*` as a positive integer"); } { // From not allowed in task deletion/cancelation queries let params = "from=12"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"Json deserialize error: unknown field `from`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``."); + snapshot!(format!("{err}"), @"Unknown parameter `from`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`"); } { // Limit not allowed in task deletion/cancelation queries let params = "limit=12"; let err = deserr_query_params::(params).unwrap_err(); - snapshot!(format!("{err}"), @"Json deserialize error: unknown field `limit`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``."); + snapshot!(format!("{err}"), @"Unknown parameter `limit`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`"); } } } diff --git a/meilisearch/src/search.rs b/meilisearch/src/search.rs index 129137859..4e2c43f18 100644 --- a/meilisearch/src/search.rs +++ b/meilisearch/src/search.rs @@ -3,10 +3,10 @@ use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::str::FromStr; use std::time::Instant; -use deserr::DeserializeFromValue; use either::Either; +use meilisearch_types::deserr::DeserializeFromValue; use meilisearch_types::error::deserr_codes::*; -use meilisearch_types::error::DeserrError; +use meilisearch_types::error::DeserrJsonError; use meilisearch_types::settings::DEFAULT_PAGINATION_MAX_TOTAL_HITS; use meilisearch_types::{milli, Document}; use milli::tokenizer::TokenizerBuilder; @@ -30,41 +30,41 @@ pub const DEFAULT_HIGHLIGHT_PRE_TAG: fn() -> String = || "".to_string(); pub const DEFAULT_HIGHLIGHT_POST_TAG: fn() -> String = || "".to_string(); #[derive(Debug, Clone, Default, PartialEq, DeserializeFromValue)] -#[deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields)] +#[deserr(error = DeserrJsonError, rename_all = camelCase, deny_unknown_fields)] pub struct SearchQuery { - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub q: Option, - #[deserr(error = DeserrError, default = DEFAULT_SEARCH_OFFSET())] + #[deserr(error = DeserrJsonError, default = DEFAULT_SEARCH_OFFSET())] pub offset: usize, - #[deserr(error = DeserrError, default = DEFAULT_SEARCH_LIMIT())] + #[deserr(error = DeserrJsonError, default = DEFAULT_SEARCH_LIMIT())] pub limit: usize, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub page: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub hits_per_page: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub attributes_to_retrieve: Option>, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub attributes_to_crop: Option>, - #[deserr(error = DeserrError, default = DEFAULT_CROP_LENGTH())] + #[deserr(error = DeserrJsonError, default = DEFAULT_CROP_LENGTH())] pub crop_length: usize, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub attributes_to_highlight: Option>, - #[deserr(error = DeserrError, default)] + #[deserr(error = DeserrJsonError, default)] pub show_matches_position: bool, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub filter: Option, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub sort: Option>, - #[deserr(error = DeserrError)] + #[deserr(error = DeserrJsonError)] pub facets: Option>, - #[deserr(error = DeserrError, default = DEFAULT_HIGHLIGHT_PRE_TAG())] + #[deserr(error = DeserrJsonError, default = DEFAULT_HIGHLIGHT_PRE_TAG())] pub highlight_pre_tag: String, - #[deserr(error = DeserrError, default = DEFAULT_HIGHLIGHT_POST_TAG())] + #[deserr(error = DeserrJsonError, default = DEFAULT_HIGHLIGHT_POST_TAG())] pub highlight_post_tag: String, - #[deserr(error = DeserrError, default = DEFAULT_CROP_MARKER())] + #[deserr(error = DeserrJsonError, default = DEFAULT_CROP_MARKER())] pub crop_marker: String, - #[deserr(error = DeserrError, default)] + #[deserr(error = DeserrJsonError, default)] pub matching_strategy: MatchingStrategy, } diff --git a/meilisearch/tests/auth/api_keys.rs b/meilisearch/tests/auth/api_keys.rs index 0a14107a8..8d7cb9130 100644 --- a/meilisearch/tests/auth/api_keys.rs +++ b/meilisearch/tests/auth/api_keys.rs @@ -248,7 +248,7 @@ async fn error_add_api_key_missing_parameter() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: missing field `indexes` at ``", + "message": "Missing field `indexes`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" @@ -265,7 +265,7 @@ async fn error_add_api_key_missing_parameter() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: missing field `actions` at ``", + "message": "Missing field `actions`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" @@ -314,7 +314,7 @@ async fn error_add_api_key_invalid_parameters_description() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Map `{\"name\":\"products\"}`, expected a String at `.description`.", + "message": "Invalid value type at `.description`: expected a string, but found an object: `{\"name\":\"products\"}`", "code": "invalid_api_key_description", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-description" @@ -337,7 +337,7 @@ async fn error_add_api_key_invalid_parameters_name() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Map `{\"name\":\"products\"}`, expected a String at `.name`.", + "message": "Invalid value type at `.name`: expected a string, but found an object: `{\"name\":\"products\"}`", "code": "invalid_api_key_name", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-name" @@ -360,7 +360,7 @@ async fn error_add_api_key_invalid_parameters_indexes() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Map `{\"name\":\"products\"}`, expected a Sequence at `.indexes`.", + "message": "Invalid value type at `.indexes`: expected an array, but found an object: `{\"name\":\"products\"}`", "code": "invalid_api_key_indexes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-indexes" @@ -386,7 +386,7 @@ async fn error_add_api_key_invalid_index_uids() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "`invalid index # / \\name with spaces` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexes[0]`.", + "message": "Invalid value at `.indexes[0]`: `invalid index # / \\name with spaces` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_).", "code": "invalid_api_key_indexes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-indexes" @@ -411,7 +411,7 @@ async fn error_add_api_key_invalid_parameters_actions() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Map `{\"name\":\"products\"}`, expected a Sequence at `.actions`.", + "message": "Invalid value type at `.actions`: expected an array, but found an object: `{\"name\":\"products\"}`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-actions" @@ -431,7 +431,7 @@ async fn error_add_api_key_invalid_parameters_actions() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: unknown value `doc.add`, expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete` at `.actions[0]`.", + "message": "Unknown value `doc.add` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-actions" @@ -455,7 +455,7 @@ async fn error_add_api_key_invalid_parameters_expires_at() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Map `{\"name\":\"products\"}`, expected a String at `.expiresAt`.", + "message": "Invalid value type at `.expiresAt`: expected a string, but found an object: `{\"name\":\"products\"}`", "code": "invalid_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-expires-at" @@ -478,7 +478,7 @@ async fn error_add_api_key_invalid_parameters_expires_at_in_the_past() { meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "`2010-11-13T00:00:00Z` is not a valid date. It should follow the RFC 3339 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'.\n at `.expiresAt`.", + "message": "Invalid value at `.expiresAt`: `2010-11-13T00:00:00Z` is not a valid date. It should follow the RFC 3339 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'.\n", "code": "invalid_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-expires-at" @@ -503,7 +503,7 @@ async fn error_add_api_key_invalid_parameters_uid() { meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid length: expected length 32 for simple format, found 13 at `.uid`.", + "message": "Invalid value at `.uid`: invalid length: expected length 32 for simple format, found 13", "code": "invalid_api_key_uid", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-uid" @@ -1403,7 +1403,7 @@ async fn error_patch_api_key_indexes() { let (response, code) = server.patch_api_key(&uid, content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: unknown field `indexes`, expected one of `description`, `name` at ``.", + "message": "Unknown field `indexes`: expected one of `description`, `name`", "code": "immutable_api_key_indexes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#immutable-api-key-indexes" @@ -1480,7 +1480,7 @@ async fn error_patch_api_key_actions() { let (response, code) = server.patch_api_key(&uid, content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: unknown field `actions`, expected one of `description`, `name` at ``.", + "message": "Unknown field `actions`: expected one of `description`, `name`", "code": "immutable_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#immutable-api-key-actions" @@ -1549,7 +1549,7 @@ async fn error_patch_api_key_expiration_date() { let (response, code) = server.patch_api_key(&uid, content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "Json deserialize error: unknown field `expiresAt`, expected one of `description`, `name` at ``.", + "message": "Unknown field `expiresAt`: expected one of `description`, `name`", "code": "immutable_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#immutable-api-key-expires-at" @@ -1670,7 +1670,7 @@ async fn error_patch_api_key_indexes_invalid_parameters() { let (response, code) = server.patch_api_key(&uid, content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Integer `13`, expected a String at `.description`.", + "message": "Invalid value type at `.description`: expected a string, but found a positive integer: `13`", "code": "invalid_api_key_description", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-description" @@ -1686,7 +1686,7 @@ async fn error_patch_api_key_indexes_invalid_parameters() { let (response, code) = server.patch_api_key(&uid, content).await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { - "message": "invalid type: Integer `13`, expected a String at `.name`.", + "message": "Invalid value type at `.name`: expected a string, but found a positive integer: `13`", "code": "invalid_api_key_name", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-api-key-name" diff --git a/meilisearch/tests/common/index.rs b/meilisearch/tests/common/index.rs index d42f18d2c..b98ed9827 100644 --- a/meilisearch/tests/common/index.rs +++ b/meilisearch/tests/common/index.rs @@ -289,8 +289,8 @@ impl Index<'_> { eprintln!("Error with post search"); resume_unwind(e); } - - let (response, code) = self.search_get(query).await; + let query = yaup::to_string(&query).unwrap(); + let (response, code) = self.search_get(&query).await; if let Err(e) = catch_unwind(move || test(response, code)) { eprintln!("Error with get search"); resume_unwind(e); @@ -302,9 +302,8 @@ impl Index<'_> { self.service.post_encoded(url, query, self.encoder).await } - pub async fn search_get(&self, query: Value) -> (Value, StatusCode) { - let params = yaup::to_string(&query).unwrap(); - let url = format!("/indexes/{}/search?{}", urlencode(self.uid.as_ref()), params); + pub async fn search_get(&self, query: &str) -> (Value, StatusCode) { + let url = format!("/indexes/{}/search?{}", urlencode(self.uid.as_ref()), query); self.service.get(url).await } diff --git a/meilisearch/tests/common/server.rs b/meilisearch/tests/common/server.rs index c3c9b7c60..e325da0cb 100644 --- a/meilisearch/tests/common/server.rs +++ b/meilisearch/tests/common/server.rs @@ -132,8 +132,8 @@ impl Server { self.service.get("/tasks").await } - pub async fn tasks_filter(&self, filter: Value) -> (Value, StatusCode) { - self.service.get(format!("/tasks?{}", yaup::to_string(&filter).unwrap())).await + pub async fn tasks_filter(&self, filter: &str) -> (Value, StatusCode) { + self.service.get(format!("/tasks?{}", filter)).await } pub async fn get_dump_status(&self, uid: &str) -> (Value, StatusCode) { @@ -148,14 +148,12 @@ impl Server { self.service.post("/swap-indexes", value).await } - pub async fn cancel_tasks(&self, value: Value) -> (Value, StatusCode) { - self.service - .post(format!("/tasks/cancel?{}", yaup::to_string(&value).unwrap()), json!(null)) - .await + pub async fn cancel_tasks(&self, value: &str) -> (Value, StatusCode) { + self.service.post(format!("/tasks/cancel?{}", value), json!(null)).await } - pub async fn delete_tasks(&self, value: Value) -> (Value, StatusCode) { - self.service.delete(format!("/tasks?{}", yaup::to_string(&value).unwrap())).await + pub async fn delete_tasks(&self, value: &str) -> (Value, StatusCode) { + self.service.delete(format!("/tasks?{}", value)).await } pub async fn wait_task(&self, update_id: u64) -> Value { diff --git a/meilisearch/tests/search/errors.rs b/meilisearch/tests/search/errors.rs index d582a3672..99f711745 100644 --- a/meilisearch/tests/search/errors.rs +++ b/meilisearch/tests/search/errors.rs @@ -46,7 +46,7 @@ async fn search_bad_q() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.q`.", + "message": "Invalid value type at `.q`: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_search_q", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-q" @@ -64,18 +64,18 @@ async fn search_bad_offset() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Integer at `.offset`.", + "message": "Invalid value type at `.offset`: expected a positive integer, but found a string: `\"doggo\"`", "code": "invalid_search_offset", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-offset" } "###); - let (response, code) = index.search_get(json!({"offset": "doggo"})).await; + let (response, code) = index.search_get("offset=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.offset`.", + "message": "Invalid value in parameter `offset`: could not parse `doggo` as a positive integer", "code": "invalid_search_offset", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-offset" @@ -92,18 +92,18 @@ async fn search_bad_limit() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Integer at `.limit`.", + "message": "Invalid value type at `.limit`: expected a positive integer, but found a string: `\"doggo\"`", "code": "invalid_search_limit", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-limit" } "###); - let (response, code) = index.search_get(json!({"limit": "doggo"})).await; + let (response, code) = index.search_get("limit=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.limit`.", + "message": "Invalid value in parameter `limit`: could not parse `doggo` as a positive integer", "code": "invalid_search_limit", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-limit" @@ -120,18 +120,18 @@ async fn search_bad_page() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Integer at `.page`.", + "message": "Invalid value type at `.page`: expected a positive integer, but found a string: `\"doggo\"`", "code": "invalid_search_page", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-page" } "###); - let (response, code) = index.search_get(json!({"page": "doggo"})).await; + let (response, code) = index.search_get("page=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.page`.", + "message": "Invalid value in parameter `page`: could not parse `doggo` as a positive integer", "code": "invalid_search_page", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-page" @@ -148,18 +148,18 @@ async fn search_bad_hits_per_page() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Integer at `.hitsPerPage`.", + "message": "Invalid value type at `.hitsPerPage`: expected a positive integer, but found a string: `\"doggo\"`", "code": "invalid_search_hits_per_page", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-hits-per-page" } "###); - let (response, code) = index.search_get(json!({"hitsPerPage": "doggo"})).await; + let (response, code) = index.search_get("hitsPerPage=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.hitsPerPage`.", + "message": "Invalid value in parameter `hitsPerPage`: could not parse `doggo` as a positive integer", "code": "invalid_search_hits_per_page", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-hits-per-page" @@ -176,7 +176,7 @@ async fn search_bad_attributes_to_crop() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.attributesToCrop`.", + "message": "Invalid value type at `.attributesToCrop`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_search_attributes_to_crop", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-attributes-to-crop" @@ -194,18 +194,18 @@ async fn search_bad_crop_length() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Integer at `.cropLength`.", + "message": "Invalid value type at `.cropLength`: expected a positive integer, but found a string: `\"doggo\"`", "code": "invalid_search_crop_length", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-crop-length" } "###); - let (response, code) = index.search_get(json!({"cropLength": "doggo"})).await; + let (response, code) = index.search_get("cropLength=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.cropLength`.", + "message": "Invalid value in parameter `cropLength`: could not parse `doggo` as a positive integer", "code": "invalid_search_crop_length", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-crop-length" @@ -222,7 +222,7 @@ async fn search_bad_attributes_to_highlight() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.attributesToHighlight`.", + "message": "Invalid value type at `.attributesToHighlight`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_search_attributes_to_highlight", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-attributes-to-highlight" @@ -266,7 +266,7 @@ async fn search_bad_sort() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.sort`.", + "message": "Invalid value type at `.sort`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_search_sort", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-sort" @@ -284,18 +284,18 @@ async fn search_bad_show_matches_position() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Boolean at `.showMatchesPosition`.", + "message": "Invalid value type at `.showMatchesPosition`: expected a boolean, but found a string: `\"doggo\"`", "code": "invalid_search_show_matches_position", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-show-matches-position" } "###); - let (response, code) = index.search_get(json!({"showMatchesPosition": "doggo"})).await; + let (response, code) = index.search_get("showMatchesPosition=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "provided string was not `true` or `false` at `.showMatchesPosition`.", + "message": "Invalid value in parameter `showMatchesPosition`: provided string was not `true` or `false`", "code": "invalid_search_show_matches_position", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-show-matches-position" @@ -312,7 +312,7 @@ async fn search_bad_facets() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.facets`.", + "message": "Invalid value type at `.facets`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_search_facets", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-facets" @@ -330,7 +330,7 @@ async fn search_bad_highlight_pre_tag() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.highlightPreTag`.", + "message": "Invalid value type at `.highlightPreTag`: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_search_highlight_pre_tag", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-highlight-pre-tag" @@ -348,7 +348,7 @@ async fn search_bad_highlight_post_tag() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.highlightPostTag`.", + "message": "Invalid value type at `.highlightPostTag`: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_search_highlight_post_tag", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-highlight-post-tag" @@ -366,7 +366,7 @@ async fn search_bad_crop_marker() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.cropMarker`.", + "message": "Invalid value type at `.cropMarker`: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_search_crop_marker", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-crop-marker" @@ -384,18 +384,18 @@ async fn search_bad_matching_strategy() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown value `doggo`, expected one of `last`, `all` at `.matchingStrategy`.", + "message": "Unknown value `doggo` at `.matchingStrategy`: expected one of `last`, `all`", "code": "invalid_search_matching_strategy", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-matching-strategy" } "###); - let (response, code) = index.search_get(json!({"matchingStrategy": "doggo"})).await; + let (response, code) = index.search_get("matchingStrategy=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown value `doggo`, expected one of `last`, `all` at `.matchingStrategy`.", + "message": "Unknown value `doggo` for parameter `matchingStrategy`: expected one of `last`, `all`", "code": "invalid_search_matching_strategy", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-search-matching-strategy" diff --git a/meilisearch/tests/settings/errors.rs b/meilisearch/tests/settings/errors.rs index 77e62303a..a3deeccfb 100644 --- a/meilisearch/tests/settings/errors.rs +++ b/meilisearch/tests/settings/errors.rs @@ -12,7 +12,7 @@ async fn settings_bad_displayed_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.displayedAttributes`.", + "message": "Invalid value type at `.displayedAttributes`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_displayed_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-displayed-attributes" @@ -23,7 +23,7 @@ async fn settings_bad_displayed_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_displayed_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-displayed-attributes" @@ -40,7 +40,7 @@ async fn settings_bad_searchable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.searchableAttributes`.", + "message": "Invalid value type at `.searchableAttributes`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_searchable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-searchable-attributes" @@ -51,7 +51,7 @@ async fn settings_bad_searchable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_searchable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-searchable-attributes" @@ -68,7 +68,7 @@ async fn settings_bad_filterable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.filterableAttributes`.", + "message": "Invalid value type at `.filterableAttributes`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_filterable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-filterable-attributes" @@ -79,7 +79,7 @@ async fn settings_bad_filterable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_filterable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-filterable-attributes" @@ -96,7 +96,7 @@ async fn settings_bad_sortable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.sortableAttributes`.", + "message": "Invalid value type at `.sortableAttributes`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_sortable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-sortable-attributes" @@ -107,7 +107,7 @@ async fn settings_bad_sortable_attributes() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_sortable_attributes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-sortable-attributes" @@ -124,7 +124,7 @@ async fn settings_bad_ranking_rules() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.rankingRules`.", + "message": "Invalid value type at `.rankingRules`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-ranking-rules" @@ -135,7 +135,7 @@ async fn settings_bad_ranking_rules() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-ranking-rules" @@ -152,7 +152,7 @@ async fn settings_bad_stop_words() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.stopWords`.", + "message": "Invalid value type at `.stopWords`: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_stop_words", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-stop-words" @@ -163,7 +163,7 @@ async fn settings_bad_stop_words() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Sequence at ``.", + "message": "Invalid value type: expected an array, but found a string: `\"doggo\"`", "code": "invalid_settings_stop_words", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-stop-words" @@ -180,7 +180,7 @@ async fn settings_bad_synonyms() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at `.synonyms`.", + "message": "Invalid value type at `.synonyms`: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_synonyms", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-synonyms" @@ -191,7 +191,7 @@ async fn settings_bad_synonyms() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at ``.", + "message": "Invalid value type: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_synonyms", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-synonyms" @@ -208,7 +208,7 @@ async fn settings_bad_distinct_attribute() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.distinctAttribute`.", + "message": "Invalid value type at `.distinctAttribute`: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_settings_distinct_attribute", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-distinct-attribute" @@ -219,7 +219,7 @@ async fn settings_bad_distinct_attribute() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at ``.", + "message": "Invalid value type: expected a string, but found an array: `[\"doggo\"]`", "code": "invalid_settings_distinct_attribute", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-distinct-attribute" @@ -236,7 +236,7 @@ async fn settings_bad_typo_tolerance() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at `.typoTolerance`.", + "message": "Invalid value type at `.typoTolerance`: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_typo_tolerance", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-typo-tolerance" @@ -247,7 +247,7 @@ async fn settings_bad_typo_tolerance() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at ``.", + "message": "Invalid value type: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_typo_tolerance", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-typo-tolerance" @@ -264,7 +264,7 @@ async fn settings_bad_faceting() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at `.faceting`.", + "message": "Invalid value type at `.faceting`: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_faceting", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-faceting" @@ -275,7 +275,7 @@ async fn settings_bad_faceting() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at ``.", + "message": "Invalid value type: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_faceting", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-faceting" @@ -292,7 +292,7 @@ async fn settings_bad_pagination() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at `.pagination`.", + "message": "Invalid value type at `.pagination`: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_pagination", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-pagination" @@ -303,7 +303,7 @@ async fn settings_bad_pagination() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid type: String `\"doggo\"`, expected a Map at ``.", + "message": "Invalid value type: expected an object, but found a string: `\"doggo\"`", "code": "invalid_settings_pagination", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-pagination" diff --git a/meilisearch/tests/settings/get_settings.rs b/meilisearch/tests/settings/get_settings.rs index 3ac7d3801..f18787e19 100644 --- a/meilisearch/tests/settings/get_settings.rs +++ b/meilisearch/tests/settings/get_settings.rs @@ -282,7 +282,7 @@ async fn error_set_invalid_ranking_rules() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "`manyTheFish` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules. at `.rankingRules[0]`.", + "message": "Invalid value at `.rankingRules[0]`: `manyTheFish` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.", "code": "invalid_settings_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-ranking-rules" diff --git a/meilisearch/tests/tasks/errors.rs b/meilisearch/tests/tasks/errors.rs index 305ab8b9c..fd4c6d489 100644 --- a/meilisearch/tests/tasks/errors.rs +++ b/meilisearch/tests/tasks/errors.rs @@ -1,5 +1,4 @@ use meili_snap::*; -use serde_json::json; use crate::common::Server; @@ -7,33 +6,44 @@ use crate::common::Server; async fn task_bad_uids() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"uids": "doggo"})).await; + let (response, code) = server.tasks_filter("uids=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `doggo` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" } "###); - let (response, code) = server.cancel_tasks(json!({"uids": "doggo"})).await; + let (response, code) = server.cancel_tasks("uids=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `doggo` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" } "###); - let (response, code) = server.delete_tasks(json!({"uids": "doggo"})).await; + let (response, code) = server.delete_tasks("uids=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `doggo` as a positive integer", + "code": "invalid_task_uids", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-task-uids" + } + "###); + + let (response, code) = server.delete_tasks("uids=1,dogo").await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value in parameter `uids`: could not parse `dogo` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" @@ -45,33 +55,33 @@ async fn task_bad_uids() { async fn task_bad_canceled_by() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"canceledBy": "doggo"})).await; + let (response, code) = server.tasks_filter("canceledBy=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.canceledBy`.", + "message": "Invalid value in parameter `canceledBy`: could not parse `doggo` as a positive integer", "code": "invalid_task_canceled_by", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-canceled-by" } "###); - let (response, code) = server.cancel_tasks(json!({"canceledBy": "doggo"})).await; + let (response, code) = server.cancel_tasks("canceledBy=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.canceledBy`.", + "message": "Invalid value in parameter `canceledBy`: could not parse `doggo` as a positive integer", "code": "invalid_task_canceled_by", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-canceled-by" } "###); - let (response, code) = server.delete_tasks(json!({"canceledBy": "doggo"})).await; + let (response, code) = server.delete_tasks("canceledBy=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.canceledBy`.", + "message": "Invalid value in parameter `canceledBy`: could not parse `doggo` as a positive integer", "code": "invalid_task_canceled_by", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-canceled-by" @@ -83,33 +93,33 @@ async fn task_bad_canceled_by() { async fn task_bad_types() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"types": "doggo"})).await; + let (response, code) = server.tasks_filter("types=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`. at `.types`.", + "message": "Invalid value in parameter `types`: `doggo` is not a valid task type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`.", "code": "invalid_task_types", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-types" } "###); - let (response, code) = server.cancel_tasks(json!({"types": "doggo"})).await; + let (response, code) = server.cancel_tasks("types=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`. at `.types`.", + "message": "Invalid value in parameter `types`: `doggo` is not a valid task type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`.", "code": "invalid_task_types", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-types" } "###); - let (response, code) = server.delete_tasks(json!({"types": "doggo"})).await; + let (response, code) = server.delete_tasks("types=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`. at `.types`.", + "message": "Invalid value in parameter `types`: `doggo` is not a valid task type. Available types are `documentAdditionOrUpdate`, `documentDeletion`, `settingsUpdate`, `indexCreation`, `indexDeletion`, `indexUpdate`, `indexSwap`, `taskCancelation`, `taskDeletion`, `dumpCreation`, `snapshotCreation`.", "code": "invalid_task_types", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-types" @@ -121,33 +131,33 @@ async fn task_bad_types() { async fn task_bad_statuses() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"statuses": "doggo"})).await; + let (response, code) = server.tasks_filter("statuses=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a status. Available status are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`. at `.statuses`.", + "message": "Invalid value in parameter `statuses`: `doggo` is not a valid task status. Available statuses are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`.", "code": "invalid_task_statuses", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-statuses" } "###); - let (response, code) = server.cancel_tasks(json!({"statuses": "doggo"})).await; + let (response, code) = server.cancel_tasks("statuses=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a status. Available status are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`. at `.statuses`.", + "message": "Invalid value in parameter `statuses`: `doggo` is not a valid task status. Available statuses are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`.", "code": "invalid_task_statuses", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-statuses" } "###); - let (response, code) = server.delete_tasks(json!({"statuses": "doggo"})).await; + let (response, code) = server.delete_tasks("statuses=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is not a status. Available status are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`. at `.statuses`.", + "message": "Invalid value in parameter `statuses`: `doggo` is not a valid task status. Available statuses are `enqueued`, `processing`, `succeeded`, `failed`, `canceled`.", "code": "invalid_task_statuses", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-statuses" @@ -159,33 +169,33 @@ async fn task_bad_statuses() { async fn task_bad_index_uids() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"indexUids": "the good doggo"})).await; + let (response, code) = server.tasks_filter("indexUids=the%20good%20doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexUids`.", + "message": "Invalid value in parameter `indexUids`: `the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_).", "code": "invalid_index_uid", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-index-uid" } "###); - let (response, code) = server.cancel_tasks(json!({"indexUids": "the good doggo"})).await; + let (response, code) = server.cancel_tasks("indexUids=the%20good%20doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexUids`.", + "message": "Invalid value in parameter `indexUids`: `the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_).", "code": "invalid_index_uid", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-index-uid" } "###); - let (response, code) = server.delete_tasks(json!({"indexUids": "the good doggo"})).await; + let (response, code) = server.delete_tasks("indexUids=the%20good%20doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_). at `.indexUids`.", + "message": "Invalid value in parameter `indexUids`: `the good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_).", "code": "invalid_index_uid", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-index-uid" @@ -197,33 +207,33 @@ async fn task_bad_index_uids() { async fn task_bad_limit() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"limit": "doggo"})).await; + let (response, code) = server.tasks_filter("limit=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.limit`.", + "message": "Invalid value in parameter `limit`: could not parse `doggo` as a positive integer", "code": "invalid_task_limit", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-limit" } "###); - let (response, code) = server.cancel_tasks(json!({"limit": "doggo"})).await; + let (response, code) = server.cancel_tasks("limit=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `limit`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `limit`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" } "###); - let (response, code) = server.delete_tasks(json!({"limit": "doggo"})).await; + let (response, code) = server.delete_tasks("limit=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `limit`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `limit`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" @@ -235,33 +245,33 @@ async fn task_bad_limit() { async fn task_bad_from() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"from": "doggo"})).await; + let (response, code) = server.tasks_filter("from=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "invalid digit found in string at `.from`.", + "message": "Invalid value in parameter `from`: could not parse `doggo` as a positive integer", "code": "invalid_task_from", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-from" } "###); - let (response, code) = server.cancel_tasks(json!({"from": "doggo"})).await; + let (response, code) = server.cancel_tasks("from=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `from`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `from`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" } "###); - let (response, code) = server.delete_tasks(json!({"from": "doggo"})).await; + let (response, code) = server.delete_tasks("from=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `from`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `from`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" @@ -273,33 +283,33 @@ async fn task_bad_from() { async fn task_bad_after_enqueued_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"afterEnqueuedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("afterEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterEnqueuedAt`.", + "message": "Invalid value in parameter `afterEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-enqueued-at" } "###); - let (response, code) = server.cancel_tasks(json!({"afterEnqueuedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("afterEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterEnqueuedAt`.", + "message": "Invalid value in parameter `afterEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-enqueued-at" } "###); - let (response, code) = server.delete_tasks(json!({"afterEnqueuedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("afterEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterEnqueuedAt`.", + "message": "Invalid value in parameter `afterEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-enqueued-at" @@ -311,33 +321,33 @@ async fn task_bad_after_enqueued_at() { async fn task_bad_before_enqueued_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"beforeEnqueuedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("beforeEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeEnqueuedAt`.", + "message": "Invalid value in parameter `beforeEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-enqueued-at" } "###); - let (response, code) = server.cancel_tasks(json!({"beforeEnqueuedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("beforeEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeEnqueuedAt`.", + "message": "Invalid value in parameter `beforeEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-enqueued-at" } "###); - let (response, code) = server.delete_tasks(json!({"beforeEnqueuedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("beforeEnqueuedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeEnqueuedAt`.", + "message": "Invalid value in parameter `beforeEnqueuedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_enqueued_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-enqueued-at" @@ -349,33 +359,33 @@ async fn task_bad_before_enqueued_at() { async fn task_bad_after_started_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"afterStartedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("afterStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterStartedAt`.", + "message": "Invalid value in parameter `afterStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-started-at" } "###); - let (response, code) = server.cancel_tasks(json!({"afterStartedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("afterStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterStartedAt`.", + "message": "Invalid value in parameter `afterStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-started-at" } "###); - let (response, code) = server.delete_tasks(json!({"afterStartedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("afterStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterStartedAt`.", + "message": "Invalid value in parameter `afterStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-started-at" @@ -387,33 +397,33 @@ async fn task_bad_after_started_at() { async fn task_bad_before_started_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"beforeStartedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("beforeStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeStartedAt`.", + "message": "Invalid value in parameter `beforeStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-started-at" } "###); - let (response, code) = server.cancel_tasks(json!({"beforeStartedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("beforeStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeStartedAt`.", + "message": "Invalid value in parameter `beforeStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-started-at" } "###); - let (response, code) = server.delete_tasks(json!({"beforeStartedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("beforeStartedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeStartedAt`.", + "message": "Invalid value in parameter `beforeStartedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-started-at" @@ -425,33 +435,33 @@ async fn task_bad_before_started_at() { async fn task_bad_after_finished_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"afterFinishedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("afterFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterFinishedAt`.", + "message": "Invalid value in parameter `afterFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-finished-at" } "###); - let (response, code) = server.cancel_tasks(json!({"afterFinishedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("afterFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterFinishedAt`.", + "message": "Invalid value in parameter `afterFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-finished-at" } "###); - let (response, code) = server.delete_tasks(json!({"afterFinishedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("afterFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.afterFinishedAt`.", + "message": "Invalid value in parameter `afterFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_after_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-after-finished-at" @@ -463,33 +473,33 @@ async fn task_bad_after_finished_at() { async fn task_bad_before_finished_at() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!({"beforeFinishedAt": "doggo"})).await; + let (response, code) = server.tasks_filter("beforeFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeFinishedAt`.", + "message": "Invalid value in parameter `beforeFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-finished-at" } "###); - let (response, code) = server.cancel_tasks(json!({"beforeFinishedAt": "doggo"})).await; + let (response, code) = server.cancel_tasks("beforeFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeFinishedAt`.", + "message": "Invalid value in parameter `beforeFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-finished-at" } "###); - let (response, code) = server.delete_tasks(json!({"beforeFinishedAt": "doggo"})).await; + let (response, code) = server.delete_tasks("beforeFinishedAt=doggo").await; snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "`doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeFinishedAt`.", + "message": "Invalid value in parameter `beforeFinishedAt`: `doggo` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_finished_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-finished-at" diff --git a/meilisearch/tests/tasks/mod.rs b/meilisearch/tests/tasks/mod.rs index 46775e05f..7fadf0a10 100644 --- a/meilisearch/tests/tasks/mod.rs +++ b/meilisearch/tests/tasks/mod.rs @@ -179,44 +179,44 @@ async fn list_tasks_status_and_type_filtered() { async fn get_task_filter_error() { let server = Server::new().await; - let (response, code) = server.tasks_filter(json!( { "lol": "pied" })).await; + let (response, code) = server.tasks_filter("lol=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `lol`, expected one of `limit`, `from`, `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `lol`: expected one of `limit`, `from`, `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" } "###); - let (response, code) = server.tasks_filter(json!( { "uids": "pied" })).await; + let (response, code) = server.tasks_filter("uids=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `pied` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" } "###); - let (response, code) = server.tasks_filter(json!( { "from": "pied" })).await; + let (response, code) = server.tasks_filter("from=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "invalid digit found in string at `.from`.", + "message": "Invalid value in parameter `from`: could not parse `pied` as a positive integer", "code": "invalid_task_from", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-from" } "###); - let (response, code) = server.tasks_filter(json!( { "beforeStartedAt": "pied" })).await; + let (response, code) = server.tasks_filter("beforeStartedAt=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "`pied` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. at `.beforeStartedAt`.", + "message": "Invalid value in parameter `beforeStartedAt`: `pied` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format.", "code": "invalid_task_before_started_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-before-started-at" @@ -228,7 +228,7 @@ async fn get_task_filter_error() { async fn delete_task_filter_error() { let server = Server::new().await; - let (response, code) = server.delete_tasks(json!(null)).await; + let (response, code) = server.delete_tasks("").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { @@ -239,22 +239,22 @@ async fn delete_task_filter_error() { } "###); - let (response, code) = server.delete_tasks(json!({ "lol": "pied" })).await; + let (response, code) = server.delete_tasks("lol=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `lol`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `lol`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" } "###); - let (response, code) = server.delete_tasks(json!({ "uids": "pied" })).await; + let (response, code) = server.delete_tasks("uids=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `pied` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" @@ -266,7 +266,7 @@ async fn delete_task_filter_error() { async fn cancel_task_filter_error() { let server = Server::new().await; - let (response, code) = server.cancel_tasks(json!(null)).await; + let (response, code) = server.cancel_tasks("").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { @@ -277,22 +277,22 @@ async fn cancel_task_filter_error() { } "###); - let (response, code) = server.cancel_tasks(json!({ "lol": "pied" })).await; + let (response, code) = server.cancel_tasks("lol=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "Json deserialize error: unknown field `lol`, expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt` at ``.", + "message": "Unknown parameter `lol`: expected one of `uids`, `canceledBy`, `types`, `statuses`, `indexUids`, `afterEnqueuedAt`, `beforeEnqueuedAt`, `afterStartedAt`, `beforeStartedAt`, `afterFinishedAt`, `beforeFinishedAt`", "code": "bad_request", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#bad-request" } "###); - let (response, code) = server.cancel_tasks(json!({ "uids": "pied" })).await; + let (response, code) = server.cancel_tasks("uids=pied").await; assert_eq!(code, 400, "{}", response); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "invalid digit found in string at `.uids`.", + "message": "Invalid value in parameter `uids`: could not parse `pied` as a positive integer", "code": "invalid_task_uids", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-task-uids" @@ -523,7 +523,7 @@ async fn test_summarized_settings_update() { meili_snap::snapshot!(code, @"400 Bad Request"); meili_snap::snapshot!(meili_snap::json_string!(response), @r###" { - "message": "`custom` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules. at `.rankingRules[0]`.", + "message": "Invalid value at `.rankingRules[0]`: `custom` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.", "code": "invalid_settings_ranking_rules", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid-settings-ranking-rules" @@ -899,7 +899,7 @@ async fn test_summarized_task_cancelation() { // to avoid being flaky we're only going to cancel an already finished task :( index.create(None).await; index.wait_task(0).await; - server.cancel_tasks(json!({ "uids": [0] })).await; + server.cancel_tasks("uids=0").await; index.wait_task(1).await; let (task, _) = index.get_task(1).await; assert_json_snapshot!(task, @@ -932,7 +932,7 @@ async fn test_summarized_task_deletion() { // to avoid being flaky we're only going to delete an already finished task :( index.create(None).await; index.wait_task(0).await; - server.delete_tasks(json!({ "uids": [0] })).await; + server.delete_tasks("uids=0").await; index.wait_task(1).await; let (task, _) = index.get_task(1).await; assert_json_snapshot!(task,