meilisearch/meilisearch-http/src/error.rs

267 lines
8.4 KiB
Rust
Raw Normal View History

use std::fmt;
use std::error;
2020-04-11 01:05:05 +08:00
use actix_http::ResponseBuilder;
2020-04-11 01:05:05 +08:00
use actix_web as aweb;
use actix_web::http::StatusCode;
2020-04-11 01:05:05 +08:00
use serde_json::json;
use actix_web::error::JsonPayloadError;
2019-10-31 22:00:36 +08:00
use meilisearch_error::{ErrorCode, Code};
#[derive(Debug)]
pub struct ResponseError {
inner: Box<dyn ErrorCode>,
}
2020-05-27 16:20:54 +08:00
impl error::Error for ResponseError {}
impl ErrorCode for ResponseError {
fn error_code(&self) -> Code {
self.inner.error_code()
}
}
impl fmt::Display for ResponseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl From<Error> for ResponseError {
fn from(error: Error) -> ResponseError {
ResponseError { inner: Box::new(error) }
}
}
#[derive(Debug)]
2020-05-20 00:20:29 +08:00
pub enum Error {
2019-10-31 22:00:36 +08:00
BadParameter(String, String),
BadRequest(String),
2019-10-31 22:00:36 +08:00
CreateIndex(String),
DocumentNotFound(String),
IndexNotFound(String),
Internal(String),
2020-03-05 18:44:30 +08:00
InvalidIndexUid,
InvalidToken(String),
2019-10-31 22:00:36 +08:00
Maintenance,
MissingAuthorizationHeader,
MissingHeader(String),
NotFound(String),
OpenIndex(String),
RetrieveDocument(u32, String),
SearchDocuments(String),
PayloadTooLarge,
UnsupportedMediaType,
2020-05-12 20:26:43 +08:00
}
impl error::Error for Error {}
impl ErrorCode for Error {
fn error_code(&self) -> Code {
2020-05-23 00:04:23 +08:00
use Error::*;
match self {
BadParameter(_, _) => Code::BadParameter,
BadRequest(_) => Code::BadRequest,
CreateIndex(_) => Code::CreateIndex,
DocumentNotFound(_) => Code::DocumentNotFound,
IndexNotFound(_) => Code::IndexNotFound,
Internal(_) => Code::Internal,
InvalidIndexUid => Code::InvalidIndexUid,
InvalidToken(_) => Code::InvalidToken,
Maintenance => Code::Maintenance,
MissingAuthorizationHeader => Code::MissingAuthorizationHeader,
MissingHeader(_) => Code::MissingHeader,
NotFound(_) => Code::NotFound,
OpenIndex(_) => Code::OpenIndex,
RetrieveDocument(_, _) => Code::RetrieveDocument,
SearchDocuments(_) => Code::SearchDocuments,
PayloadTooLarge => Code::PayloadTooLarge,
UnsupportedMediaType => Code::UnsupportedMediaType,
}
}
}
#[derive(Debug)]
2020-05-12 20:26:43 +08:00
pub enum FacetCountError {
AttributeNotSet(String),
SyntaxError(String),
UnexpectedToken { found: String, expected: &'static [&'static str] },
NoFacetSet,
}
impl error::Error for FacetCountError {}
impl ErrorCode for FacetCountError {
fn error_code(&self) -> Code {
2020-05-23 00:04:23 +08:00
Code::BadRequest
}
}
2020-05-12 20:26:43 +08:00
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<serde_json::error::Error> 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"),
}
}
}
2020-05-20 00:20:29 +08:00
impl Error {
pub fn internal(err: impl fmt::Display) -> Error {
Error::Internal(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn bad_request(err: impl fmt::Display) -> Error {
Error::BadRequest(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn missing_authorization_header() -> Error {
Error::MissingAuthorizationHeader
}
2020-05-20 00:20:29 +08:00
pub fn invalid_token(err: impl fmt::Display) -> Error {
Error::InvalidToken(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn not_found(err: impl fmt::Display) -> Error {
Error::NotFound(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn index_not_found(err: impl fmt::Display) -> Error {
Error::IndexNotFound(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn document_not_found(err: impl fmt::Display) -> Error {
Error::DocumentNotFound(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn missing_header(err: impl fmt::Display) -> Error {
Error::MissingHeader(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn bad_parameter(param: impl fmt::Display, err: impl fmt::Display) -> Error {
Error::BadParameter(param.to_string(), err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn open_index(err: impl fmt::Display) -> Error {
Error::OpenIndex(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn create_index(err: impl fmt::Display) -> Error {
Error::CreateIndex(err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn invalid_index_uid() -> Error {
Error::InvalidIndexUid
}
2020-05-20 00:20:29 +08:00
pub fn maintenance() -> Error {
Error::Maintenance
}
2020-05-23 00:04:23 +08:00
pub fn retrieve_document(doc_id: u32, err: impl fmt::Display) -> Error {
2020-05-20 00:20:29 +08:00
Error::RetrieveDocument(doc_id, err.to_string())
}
2020-05-20 00:20:29 +08:00
pub fn search_documents(err: impl fmt::Display) -> Error {
Error::SearchDocuments(err.to_string())
}
2019-10-31 22:00:36 +08:00
}
2020-05-20 00:20:29 +08:00
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::BadParameter(param, err) => write!(f, "Url parameter {} error: {}", param, err),
2020-04-24 21:00:52 +08:00
Self::BadRequest(err) => f.write_str(err),
Self::CreateIndex(err) => write!(f, "Impossible to create index; {}", err),
Self::DocumentNotFound(document_id) => write!(f, "Document with id {} not found", document_id),
Self::IndexNotFound(index_uid) => write!(f, "Index {} not found", index_uid),
2020-04-24 21:00:52 +08:00
Self::Internal(err) => f.write_str(err),
Self::InvalidIndexUid => f.write_str("Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_)."),
Self::InvalidToken(err) => write!(f, "Invalid API key: {}", err),
Self::Maintenance => f.write_str("Server is in maintenance, please try again later"),
Self::MissingAuthorizationHeader => f.write_str("You must have an authorization token"),
Self::MissingHeader(header) => write!(f, "Header {} is missing", header),
Self::NotFound(err) => write!(f, "{} not found", err),
Self::OpenIndex(err) => write!(f, "Impossible to open index; {}", err),
Self::RetrieveDocument(id, err) => write!(f, "impossible to retrieve the document with id: {}; {}", id, err),
Self::SearchDocuments(err) => write!(f, "impossible to search documents; {}", err),
Self::PayloadTooLarge => f.write_str("Payload to large"),
2020-05-12 21:23:35 +08:00
Self::UnsupportedMediaType => f.write_str("Unsupported media type"),
}
2019-10-31 22:00:36 +08:00
}
}
impl aweb::error::ResponseError for ResponseError {
2020-04-09 16:39:34 +08:00
fn error_response(&self) -> aweb::HttpResponse {
ResponseBuilder::new(self.status_code()).json(json!({
"message": self.to_string(),
2020-05-27 16:20:54 +08:00
"errorCode": self.error_name(),
"errorType": self.error_type(),
"errorLink": self.error_url(),
}))
}
fn status_code(&self) -> StatusCode {
2020-05-27 16:20:54 +08:00
self.http_status()
2019-10-31 22:00:36 +08:00
}
}
impl From<meilisearch_core::Error> for ResponseError {
fn from(err: meilisearch_core::Error) -> ResponseError {
ResponseError { inner: Box::new(err) }
}
}
impl From<meilisearch_schema::Error> for ResponseError {
fn from(err: meilisearch_schema::Error) -> ResponseError {
ResponseError { inner: Box::new(err) }
}
}
2020-05-20 00:20:29 +08:00
impl From<actix_http::Error> for Error {
fn from(err: actix_http::Error) -> Error {
Error::Internal(err.to_string())
}
}
impl From<FacetCountError> for ResponseError {
fn from(err: FacetCountError) -> ResponseError {
ResponseError { inner: Box::new(err) }
2020-05-12 20:26:43 +08:00
}
}
2020-05-20 00:20:29 +08:00
impl From<JsonPayloadError> for Error {
fn from(err: JsonPayloadError) -> Error {
match err {
2020-05-20 00:20:29 +08:00
JsonPayloadError::Deserialize(err) => Error::BadRequest(format!("Invalid JSON: {}", err)),
JsonPayloadError::Overflow => Error::PayloadTooLarge,
JsonPayloadError::ContentType => Error::UnsupportedMediaType,
JsonPayloadError::Payload(err) => Error::BadRequest(format!("Problem while decoding the request: {}", err)),
2020-05-12 20:26:43 +08:00
}
}
}
pub fn json_error_handler(err: JsonPayloadError) -> ResponseError {
let error = Error::from(err);
error.into()
}