MeiliSearch/meilisearch-http/src/error.rs

184 lines
5.1 KiB
Rust
Raw Normal View History

2020-12-12 13:32:06 +01:00
use std::error;
use std::error::Error;
2020-12-12 13:32:06 +01:00
use std::fmt;
use actix_web as aweb;
2021-04-21 13:49:21 +02:00
use actix_web::body::Body;
use actix_web::dev::BaseHttpResponseBuilder;
2020-12-12 13:32:06 +01:00
use actix_web::http::StatusCode;
2021-03-15 18:11:10 +01:00
use meilisearch_error::{Code, ErrorCode};
2021-06-17 14:36:32 +02:00
use milli::UserError;
2021-03-15 18:11:10 +01:00
use serde::ser::{Serialize, SerializeStruct, Serializer};
2020-12-22 14:02:41 +01:00
use crate::index_controller::error::IndexControllerError;
#[derive(Debug, thiserror::Error)]
pub enum AuthenticationError {
2021-06-21 13:57:32 +02:00
#[error("you must have an authorization token")]
MissingAuthorizationHeader,
2021-06-21 13:57:32 +02:00
#[error("invalid API key")]
InvalidToken(String),
}
impl ErrorCode for AuthenticationError {
fn error_code(&self) -> Code {
match self {
2021-06-15 17:39:07 +02:00
AuthenticationError::MissingAuthorizationHeader => Code::MissingAuthorizationHeader,
AuthenticationError::InvalidToken(_) => Code::InvalidToken,
}
}
}
2020-12-12 13:32:06 +01:00
#[derive(Debug)]
pub struct ResponseError {
inner: Box<dyn ErrorCode>,
}
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)
}
}
macro_rules! response_error {
($($other:path), *) => {
$(
impl From<$other> for ResponseError {
fn from(error: $other) -> ResponseError {
ResponseError {
inner: Box::new(error),
}
}
}
2021-02-04 12:34:12 +01:00
)*
};
2020-12-12 13:32:06 +01:00
}
2021-06-15 17:39:07 +02:00
response_error!(IndexControllerError, AuthenticationError);
2020-12-12 13:32:06 +01:00
impl Serialize for ResponseError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let struct_name = "ResponseError";
let field_count = 4;
let mut state = serializer.serialize_struct(struct_name, field_count)?;
state.serialize_field("message", &self.to_string())?;
state.serialize_field("errorCode", &self.error_name())?;
state.serialize_field("errorType", &self.error_type())?;
state.serialize_field("errorLink", &self.error_url())?;
state.end()
}
}
impl aweb::error::ResponseError for ResponseError {
2021-04-21 13:49:21 +02:00
fn error_response(&self) -> aweb::BaseHttpResponse<Body> {
let json = serde_json::to_vec(self).unwrap();
BaseHttpResponseBuilder::new(self.status_code()).body(json)
2020-12-12 13:32:06 +01:00
}
fn status_code(&self) -> StatusCode {
self.http_status()
}
}
#[derive(Debug)]
struct PayloadError<E>(E);
2020-12-12 13:32:06 +01:00
impl<E: Error> fmt::Display for PayloadError<E> {
2020-12-12 13:32:06 +01:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.0, f)
2020-12-12 13:32:06 +01:00
}
}
impl<E: Error> Error for PayloadError<E> {}
2020-12-12 13:32:06 +01:00
impl<E: Error> ErrorCode for PayloadError<E> {
fn error_code(&self) -> Code {
Code::Internal
2020-12-12 13:32:06 +01:00
}
}
impl<E> From<PayloadError<E>> for ResponseError
2021-06-15 17:39:07 +02:00
where
E: Error + Sync + Send + 'static,
{
fn from(other: PayloadError<E>) -> Self {
ResponseError {
inner: Box::new(other),
2020-12-12 13:32:06 +01:00
}
}
}
pub fn payload_error_handler<E>(err: E) -> ResponseError
2021-06-15 17:39:07 +02:00
where
E: Error + Sync + Send + 'static,
{
let error = PayloadError(err);
2020-12-12 13:32:06 +01:00
error.into()
}
2021-06-15 17:55:27 +02:00
macro_rules! internal_error {
($target:ty : $($other:path), *) => {
$(
impl From<$other> for $target {
fn from(other: $other) -> Self {
Self::Internal(Box::new(other))
}
}
)*
}
}
2021-06-17 14:36:32 +02:00
#[derive(Debug)]
pub struct MilliError<'a>(pub &'a milli::Error);
impl Error for MilliError<'_> {}
impl fmt::Display for MilliError<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl ErrorCode for MilliError<'_> {
fn error_code(&self) -> Code {
match self.0 {
milli::Error::InternalError(_) => Code::Internal,
milli::Error::IoError(_) => Code::Internal,
milli::Error::UserError(ref error) => {
match error {
// TODO: wait for spec for new error codes.
UserError::AttributeLimitReached
| UserError::Csv(_)
| UserError::SerdeJson(_)
| UserError::MaxDatabaseSizeReached
| UserError::InvalidCriterionName { .. }
| UserError::InvalidDocumentId { .. }
| UserError::InvalidStoreFile
| UserError::NoSpaceLeftOnDevice
| UserError::DocumentLimitReached => todo!(),
UserError::InvalidFilter(_) => Code::Filter,
UserError::InvalidFilterAttribute(_) => Code::Filter,
UserError::MissingDocumentId { .. } => Code::MissingDocumentId,
UserError::MissingPrimaryKey => Code::MissingPrimaryKey,
UserError::PrimaryKeyCannotBeChanged => Code::PrimaryKeyAlreadyPresent,
UserError::PrimaryKeyCannotBeReset => Code::PrimaryKeyAlreadyPresent,
UserError::UnknownInternalDocumentId { .. } => Code::DocumentNotFound,
}
2021-06-17 14:38:52 +02:00
}
2021-06-17 14:36:32 +02:00
}
}
}