MeiliSearch/meilisearch-http/src/error.rs

184 lines
5.7 KiB
Rust
Raw Normal View History

2019-10-31 15:00:36 +01:00
use std::fmt::Display;
use http::status::StatusCode;
use log::{error, warn};
2020-02-11 15:16:02 +01:00
use meilisearch_core::{FstError, HeedError};
2019-10-31 15:00:36 +01:00
use serde::{Deserialize, Serialize};
2020-01-15 17:10:33 +01:00
use tide::IntoResponse;
2019-10-31 15:00:36 +01:00
use tide::Response;
2020-01-16 16:58:57 +01:00
use crate::helpers::meilisearch::Error as SearchError;
2019-10-31 15:00:36 +01:00
pub type SResult<T> = Result<T, ResponseError>;
pub enum ResponseError {
Internal(String),
BadRequest(String),
InvalidToken(String),
NotFound(String),
IndexNotFound(String),
DocumentNotFound(String),
MissingHeader(String),
BadParameter(String, String),
OpenIndex(String),
2019-10-31 15:00:36 +01:00
CreateIndex(String),
2020-03-05 11:44:30 +01:00
InvalidIndexUid,
2019-10-31 15:00:36 +01:00
Maintenance,
}
impl ResponseError {
pub fn internal(message: impl Display) -> ResponseError {
ResponseError::Internal(message.to_string())
}
pub fn bad_request(message: impl Display) -> ResponseError {
ResponseError::BadRequest(message.to_string())
}
pub fn invalid_token(message: impl Display) -> ResponseError {
ResponseError::InvalidToken(message.to_string())
}
pub fn not_found(message: impl Display) -> ResponseError {
ResponseError::NotFound(message.to_string())
}
pub fn index_not_found(message: impl Display) -> ResponseError {
ResponseError::IndexNotFound(message.to_string())
}
pub fn document_not_found(message: impl Display) -> ResponseError {
ResponseError::DocumentNotFound(message.to_string())
}
pub fn missing_header(message: impl Display) -> ResponseError {
ResponseError::MissingHeader(message.to_string())
}
pub fn bad_parameter(name: impl Display, message: impl Display) -> ResponseError {
ResponseError::BadParameter(name.to_string(), message.to_string())
}
pub fn open_index(message: impl Display) -> ResponseError {
ResponseError::OpenIndex(message.to_string())
}
2019-10-31 15:00:36 +01:00
pub fn create_index(message: impl Display) -> ResponseError {
ResponseError::CreateIndex(message.to_string())
}
}
impl IntoResponse for ResponseError {
fn into_response(self) -> Response {
match self {
ResponseError::Internal(err) => {
error!("internal server error: {}", err);
error(
String::from("Internal server error"),
StatusCode::INTERNAL_SERVER_ERROR,
)
}
ResponseError::BadRequest(err) => {
warn!("bad request: {}", err);
error(err, StatusCode::BAD_REQUEST)
}
ResponseError::InvalidToken(err) => {
2019-12-12 15:39:32 +01:00
error(format!("Invalid API key: {}", err), StatusCode::FORBIDDEN)
2019-10-31 15:00:36 +01:00
}
ResponseError::NotFound(err) => error(err, StatusCode::NOT_FOUND),
ResponseError::IndexNotFound(index) => {
error(format!("Index {} not found", index), StatusCode::NOT_FOUND)
}
ResponseError::DocumentNotFound(id) => error(
format!("Document with id {} not found", id),
StatusCode::NOT_FOUND,
),
ResponseError::MissingHeader(header) => error(
format!("Header {} is missing", header),
StatusCode::UNAUTHORIZED,
),
ResponseError::BadParameter(param, e) => error(
format!("Url parameter {} error: {}", param, e),
StatusCode::BAD_REQUEST,
),
ResponseError::CreateIndex(err) => error(
format!("Impossible to create index; {}", err),
StatusCode::BAD_REQUEST,
),
ResponseError::OpenIndex(err) => error(
format!("Impossible to open index; {}", err),
StatusCode::BAD_REQUEST,
),
2020-03-05 11:44:30 +01:00
ResponseError::InvalidIndexUid => error(
"Index must have a valid uid; Index uid can be of type integer or string only composed of alphanumeric characters, hyphens (-) and underscores (_).".to_string(),
StatusCode::BAD_REQUEST,
),
2019-10-31 15:00:36 +01:00
ResponseError::Maintenance => error(
String::from("Server is in maintenance, please try again later"),
StatusCode::SERVICE_UNAVAILABLE,
),
}
}
}
#[derive(Serialize, Deserialize)]
struct ErrorMessage {
message: String,
}
fn error(message: String, status: StatusCode) -> Response {
let message = ErrorMessage { message };
2020-01-23 11:30:18 +01:00
tide::Response::new(status.as_u16())
.body_json(&message)
.unwrap()
2019-10-31 15:00:36 +01:00
}
2020-01-16 16:58:57 +01:00
2020-01-29 18:30:21 +01:00
impl From<serde_json::Error> for ResponseError {
fn from(err: serde_json::Error) -> ResponseError {
ResponseError::internal(err)
}
}
2020-01-16 16:58:57 +01:00
impl From<meilisearch_core::Error> for ResponseError {
fn from(err: meilisearch_core::Error) -> ResponseError {
ResponseError::internal(err)
}
}
2020-02-02 22:59:19 +01:00
impl From<HeedError> for ResponseError {
fn from(err: HeedError) -> ResponseError {
2020-01-16 16:58:57 +01:00
ResponseError::internal(err)
}
}
2020-02-02 22:59:19 +01:00
impl From<FstError> for ResponseError {
fn from(err: FstError) -> ResponseError {
2020-01-16 16:58:57 +01:00
ResponseError::internal(err)
}
}
impl From<SearchError> for ResponseError {
fn from(err: SearchError) -> ResponseError {
ResponseError::internal(err)
}
}
2020-01-29 18:30:21 +01:00
impl From<meilisearch_core::settings::RankingRuleConversionError> for ResponseError {
fn from(err: meilisearch_core::settings::RankingRuleConversionError) -> ResponseError {
ResponseError::internal(err)
}
}
2020-01-16 16:58:57 +01:00
pub trait IntoInternalError<T> {
fn into_internal_error(self) -> SResult<T>;
}
2020-01-23 11:30:18 +01:00
impl<T> IntoInternalError<T> for Option<T> {
2020-01-16 16:58:57 +01:00
fn into_internal_error(self) -> SResult<T> {
match self {
Some(value) => Ok(value),
2020-01-23 11:30:18 +01:00
None => Err(ResponseError::internal("Heed cannot find requested value")),
2020-01-16 16:58:57 +01:00
}
}
}