From 5051a796a082877dd84e445ab769951af3245a83 Mon Sep 17 00:00:00 2001 From: mpostma Date: Tue, 12 May 2020 14:26:43 +0200 Subject: [PATCH] error handling --- meilisearch-http/src/error.rs | 59 +++++++++++++++++++++++---- meilisearch-http/src/routes/search.rs | 11 +++-- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/meilisearch-http/src/error.rs b/meilisearch-http/src/error.rs index e79cb56b6..eee9d8e8e 100644 --- a/meilisearch-http/src/error.rs +++ b/meilisearch-http/src/error.rs @@ -27,6 +27,40 @@ pub enum ResponseError { PayloadTooLarge, UnsupportedMediaType, FacetExpression(String), + FacetCount(String), +} + +pub enum FacetCountError { + AttributeNotSet(String), + SyntaxError(String), + UnexpectedToken { found: String, expected: &'static [&'static str] }, + NoFacetSet, +} + +impl FacetCountError { + pub fn unexpected_token(found: impl ToString, expected: &'static [&'static str]) -> FacetCountError { + let found = found.to_string(); + FacetCountError::UnexpectedToken { expected, found } + } +} + +impl From for FacetCountError { + fn from(other: serde_json::error::Error) -> FacetCountError { + FacetCountError::SyntaxError(other.to_string()) + } +} + +impl fmt::Display for FacetCountError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use FacetCountError::*; + + match self { + AttributeNotSet(attr) => write!(f, "attribute {} is not set as facet", attr), + SyntaxError(msg) => write!(f, "syntax error: {}", msg), + UnexpectedToken { expected, found } => write!(f, "unexpected {} found, expected {:?}", found, expected), + NoFacetSet => write!(f, "can't perform facet count, as no facet is set"), + } + } } impl ResponseError { @@ -113,6 +147,7 @@ impl fmt::Display for ResponseError { Self::FacetExpression(e) => write!(f, "error parsing facet filter expression: {}", e), Self::PayloadTooLarge => f.write_str("Payload to large"), Self::UnsupportedMediaType => f.write_str("Unsupported media type") + Self::FacetCount(e) => write!(f, "error with facet count: {}", e), } } } @@ -134,6 +169,7 @@ impl aweb::error::ResponseError for ResponseError { | Self::RetrieveDocument(_, _) | Self::FacetExpression(_) | Self::SearchDocuments(_) + | Self::FacetCount(_) | Self::FilterParsing(_) => StatusCode::BAD_REQUEST, Self::DocumentNotFound(_) | Self::IndexNotFound(_) @@ -198,18 +234,23 @@ impl From for ResponseError { } } -impl From for ResponseError { - fn from(err: JsonPayloadError) -> ResponseError { - match err { - JsonPayloadError::Deserialize(err) => ResponseError::BadRequest(format!("Invalid JSON: {}", err)), - JsonPayloadError::Overflow => ResponseError::PayloadTooLarge, - JsonPayloadError::ContentType => ResponseError::UnsupportedMediaType, - JsonPayloadError::Payload(err) => ResponseError::BadRequest(format!("Problem while decoding the request: {}", err)), - } +impl From for ResponseError { + fn from(other: FacetCountError) -> ResponseError { + ResponseError::FacetCount(other.to_string()) } } +impl From for ResponseError { + fn from(err: JsonPayloadError) -> ResponseError { + match err { + JsonPayloadError::Deserialize(err) => ResponseError::BadRequest(format!("Invalid JSON: {}", err)), + JsonPayloadError::Overflow => ResponseError::PayloadTooLarge, + JsonPayloadError::ContentType => ResponseError::UnsupportedMediaType, + JsonPayloadError::Payload(err) => ResponseError::BadRequest(format!("Problem while decoding the request: {}", err)), + } + } +} pub fn json_error_handler(err: JsonPayloadError) -> ResponseError { - err.into() + err.into() } diff --git a/meilisearch-http/src/routes/search.rs b/meilisearch-http/src/routes/search.rs index 5d086d128..7739ea1d8 100644 --- a/meilisearch-http/src/routes/search.rs +++ b/meilisearch-http/src/routes/search.rs @@ -7,7 +7,7 @@ use actix_web_macros::get; use serde::Deserialize; use serde_json::Value; -use crate::error::ResponseError; +use crate::error::{ResponseError, FacetCountError}; use crate::helpers::meilisearch::IndexSearchExt; use crate::helpers::Authentication; use crate::routes::IndexParam; @@ -100,9 +100,8 @@ async fn search_with_url_query( let field_ids = prepare_facet_list(&facets, &schema, attrs)?; search_builder.add_facets(field_ids); }, - None => return Err(ResponseError::FacetExpression("can't return facets count, as no facet is set".to_string())) + None => return Err(FacetCountError::NoFacetSet.into()) } - } if let Some(attributes_to_crop) = ¶ms.attributes_to_crop { @@ -188,16 +187,16 @@ fn prepare_facet_list(facets: &str, schema: &Schema, facet_attrs: &[FieldId]) -> Value::String(facet) => { if let Some(id) = schema.id(&facet) { if !facet_attrs.contains(&id) { - return Err(ResponseError::FacetExpression("Only attributes set as facet can be counted".to_string())); // TODO make special error + return Err(FacetCountError::AttributeNotSet(facet)); } field_ids.push((id, facet)); } } - bad_val => return Err(ResponseError::FacetExpression(format!("expected String found {}", bad_val))) + bad_val => return Err(FacetCountError::unexpected_token(bad_val, &["String"])), } } Ok(field_ids) } - bad_val => return Err(ResponseError::FacetExpression(format!("expected Array found {}", bad_val))) + bad_val => return Err(FacetCountError::unexpected_token(bad_val, &["[String]"])) } }