2020-05-19 18:13:02 +02:00
|
|
|
use std::fmt;
|
2020-05-27 10:20:54 +02:00
|
|
|
|
2020-05-19 18:13:02 +02:00
|
|
|
use actix_http::http::StatusCode;
|
|
|
|
|
|
|
|
pub trait ErrorCode: std::error::Error {
|
|
|
|
fn error_code(&self) -> Code;
|
2020-05-27 10:20:54 +02:00
|
|
|
|
|
|
|
/// returns the HTTP status code ascociated with the error
|
|
|
|
fn http_status(&self) -> StatusCode {
|
|
|
|
self.error_code().http()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// returns the doc url ascociated with the error
|
|
|
|
fn error_url(&self) -> String {
|
|
|
|
self.error_code().url()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// returns error name, used as error code
|
|
|
|
fn error_name(&self) -> String {
|
|
|
|
self.error_code().name()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return the error type
|
|
|
|
fn error_type(&self) -> String {
|
2020-05-28 16:12:24 +02:00
|
|
|
self.error_code().type_()
|
2020-05-27 10:20:54 +02:00
|
|
|
}
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:09:34 +02:00
|
|
|
#[allow(clippy::enum_variant_names)]
|
2020-05-25 19:11:38 +02:00
|
|
|
enum ErrorType {
|
|
|
|
InternalError,
|
2020-05-29 16:29:46 +02:00
|
|
|
InvalidRequestError,
|
|
|
|
AuthenticationError,
|
2020-05-25 19:11:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for ErrorType {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use ErrorType::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
InternalError => write!(f, "internal_error"),
|
2020-05-29 16:29:46 +02:00
|
|
|
InvalidRequestError => write!(f, "invalid_request_error"),
|
|
|
|
AuthenticationError => write!(f, "authentication_error"),
|
2020-05-25 19:11:38 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Code {
|
2020-05-26 11:32:03 +02:00
|
|
|
// index related error
|
|
|
|
CreateIndex,
|
|
|
|
IndexAlreadyExists,
|
|
|
|
IndexNotFound,
|
|
|
|
InvalidIndexUid,
|
|
|
|
OpenIndex,
|
|
|
|
|
|
|
|
// invalid state error
|
|
|
|
InvalidState,
|
|
|
|
MissingPrimaryKey,
|
2020-05-26 12:17:53 +02:00
|
|
|
PrimaryKeyAlreadyPresent,
|
2020-05-26 11:32:03 +02:00
|
|
|
|
|
|
|
MaxFieldsLimitExceeded,
|
2020-05-27 12:04:35 +02:00
|
|
|
MissingDocumentId,
|
2020-05-26 11:32:03 +02:00
|
|
|
|
|
|
|
Facet,
|
2020-05-27 12:04:35 +02:00
|
|
|
Filter,
|
2020-05-26 11:32:03 +02:00
|
|
|
|
2020-05-22 18:04:23 +02:00
|
|
|
BadParameter,
|
|
|
|
BadRequest,
|
|
|
|
DocumentNotFound,
|
|
|
|
Internal,
|
|
|
|
InvalidToken,
|
|
|
|
Maintenance,
|
|
|
|
MissingAuthorizationHeader,
|
|
|
|
NotFound,
|
2020-05-27 12:04:35 +02:00
|
|
|
PayloadTooLarge,
|
2020-05-22 18:04:23 +02:00
|
|
|
RetrieveDocument,
|
|
|
|
SearchDocuments,
|
|
|
|
UnsupportedMediaType,
|
2020-07-28 14:41:49 +02:00
|
|
|
|
2020-09-29 12:18:09 +02:00
|
|
|
DumpAlreadyInProgress,
|
|
|
|
DumpProcessFailed,
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
|
2020-05-22 18:04:23 +02:00
|
|
|
impl Code {
|
|
|
|
|
|
|
|
/// ascociate a `Code` variant to the actual ErrCode
|
|
|
|
fn err_code(&self) -> ErrCode {
|
|
|
|
use Code::*;
|
|
|
|
|
|
|
|
match self {
|
2020-05-26 11:32:03 +02:00
|
|
|
// index related errors
|
2020-06-22 16:09:57 +02:00
|
|
|
// create index is thrown on internal error while creating an index.
|
2020-06-22 16:09:57 +02:00
|
|
|
CreateIndex => ErrCode::internal("index_creation_failed", StatusCode::BAD_REQUEST),
|
2020-05-29 16:28:11 +02:00
|
|
|
IndexAlreadyExists => ErrCode::invalid("index_already_exists", StatusCode::BAD_REQUEST),
|
2020-06-22 16:09:57 +02:00
|
|
|
// thrown when requesting an unexisting index
|
2020-06-22 16:09:57 +02:00
|
|
|
IndexNotFound => ErrCode::invalid("index_not_found", StatusCode::NOT_FOUND),
|
|
|
|
InvalidIndexUid => ErrCode::invalid("invalid_index_uid", StatusCode::BAD_REQUEST),
|
2020-06-29 14:37:51 +02:00
|
|
|
OpenIndex => ErrCode::internal("index_not_accessible", StatusCode::INTERNAL_SERVER_ERROR),
|
2020-05-26 11:32:03 +02:00
|
|
|
|
|
|
|
// invalid state error
|
|
|
|
InvalidState => ErrCode::internal("invalid_state", StatusCode::INTERNAL_SERVER_ERROR),
|
2020-06-22 16:09:57 +02:00
|
|
|
// thrown when no primary key has been set
|
2020-07-06 09:56:10 +02:00
|
|
|
MissingPrimaryKey => ErrCode::invalid("missing_primary_key", StatusCode::BAD_REQUEST),
|
2020-06-22 16:09:57 +02:00
|
|
|
// error thrown when trying to set an already existing primary key
|
|
|
|
PrimaryKeyAlreadyPresent => ErrCode::invalid("primary_key_already_present", StatusCode::BAD_REQUEST),
|
2020-05-26 11:32:03 +02:00
|
|
|
|
|
|
|
// invalid document
|
2020-06-24 11:33:16 +02:00
|
|
|
MaxFieldsLimitExceeded => ErrCode::invalid("max_fields_limit_exceeded", StatusCode::BAD_REQUEST),
|
2020-05-27 12:04:35 +02:00
|
|
|
MissingDocumentId => ErrCode::invalid("missing_document_id", StatusCode::BAD_REQUEST),
|
2020-05-26 11:32:03 +02:00
|
|
|
|
2020-06-22 16:09:57 +02:00
|
|
|
// error related to facets
|
2020-05-27 12:04:35 +02:00
|
|
|
Facet => ErrCode::invalid("invalid_facet", StatusCode::BAD_REQUEST),
|
2020-06-22 16:09:57 +02:00
|
|
|
// error related to filters
|
2020-05-27 12:04:35 +02:00
|
|
|
Filter => ErrCode::invalid("invalid_filter", StatusCode::BAD_REQUEST),
|
2020-05-26 11:32:03 +02:00
|
|
|
|
|
|
|
BadParameter => ErrCode::invalid("bad_parameter", StatusCode::BAD_REQUEST),
|
|
|
|
BadRequest => ErrCode::invalid("bad_request", StatusCode::BAD_REQUEST),
|
2020-06-22 16:09:57 +02:00
|
|
|
DocumentNotFound => ErrCode::invalid("document_not_found", StatusCode::NOT_FOUND),
|
2020-05-27 12:04:35 +02:00
|
|
|
Internal => ErrCode::internal("internal", StatusCode::INTERNAL_SERVER_ERROR),
|
2020-06-04 14:57:16 +02:00
|
|
|
InvalidToken => ErrCode::authentication("invalid_token", StatusCode::FORBIDDEN),
|
2020-05-27 12:04:35 +02:00
|
|
|
Maintenance => ErrCode::internal("maintenance", StatusCode::SERVICE_UNAVAILABLE),
|
2020-06-04 14:57:16 +02:00
|
|
|
MissingAuthorizationHeader => ErrCode::authentication("missing_authorization_header", StatusCode::UNAUTHORIZED),
|
2020-05-27 12:04:35 +02:00
|
|
|
NotFound => ErrCode::invalid("not_found", StatusCode::NOT_FOUND),
|
2020-05-26 13:41:34 +02:00
|
|
|
PayloadTooLarge => ErrCode::invalid("payload_too_large", StatusCode::PAYLOAD_TOO_LARGE),
|
2020-06-29 14:37:51 +02:00
|
|
|
RetrieveDocument => ErrCode::internal("unretrievable_document", StatusCode::BAD_REQUEST),
|
2020-05-27 12:04:35 +02:00
|
|
|
SearchDocuments => ErrCode::internal("search_error", StatusCode::BAD_REQUEST),
|
2020-05-26 13:41:34 +02:00
|
|
|
UnsupportedMediaType => ErrCode::invalid("unsupported_media_type", StatusCode::UNSUPPORTED_MEDIA_TYPE),
|
2020-07-28 14:41:49 +02:00
|
|
|
|
2020-09-29 12:18:09 +02:00
|
|
|
// error related to dump
|
|
|
|
DumpAlreadyInProgress => ErrCode::invalid("dump_already_in_progress", StatusCode::CONFLICT),
|
|
|
|
DumpProcessFailed => ErrCode::internal("dump_process_failed", StatusCode::INTERNAL_SERVER_ERROR),
|
2020-05-22 18:04:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// return the HTTP status code ascociated with the `Code`
|
2020-05-27 10:20:54 +02:00
|
|
|
fn http(&self) -> StatusCode {
|
2020-05-25 19:11:38 +02:00
|
|
|
self.err_code().status_code
|
2020-05-22 18:04:23 +02:00
|
|
|
}
|
|
|
|
|
2020-05-25 19:11:38 +02:00
|
|
|
/// return error name, used as error code
|
2020-05-27 10:20:54 +02:00
|
|
|
fn name(&self) -> String {
|
2020-05-27 12:04:35 +02:00
|
|
|
self.err_code().error_name.to_string()
|
2020-05-22 18:04:23 +02:00
|
|
|
}
|
|
|
|
|
2020-05-25 19:11:38 +02:00
|
|
|
/// return the error type
|
2020-05-28 16:12:24 +02:00
|
|
|
fn type_(&self) -> String {
|
2020-05-27 12:04:35 +02:00
|
|
|
self.err_code().error_type.to_string()
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
2020-05-26 13:41:34 +02:00
|
|
|
|
2020-05-27 10:20:54 +02:00
|
|
|
/// return the doc url ascociated with the error
|
|
|
|
fn url(&self) -> String {
|
2020-07-16 15:14:53 +02:00
|
|
|
format!("https://docs.meilisearch.com/errors#{}", self.name())
|
2020-05-26 13:41:34 +02:00
|
|
|
}
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Internal structure providing a convenient way to create error codes
|
|
|
|
struct ErrCode {
|
2020-05-25 19:11:38 +02:00
|
|
|
status_code: StatusCode,
|
2020-05-27 12:04:35 +02:00
|
|
|
error_type: ErrorType,
|
|
|
|
error_name: &'static str,
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ErrCode {
|
2020-05-28 16:12:24 +02:00
|
|
|
fn authentication(error_name: &'static str, status_code: StatusCode) -> ErrCode {
|
2020-05-19 18:13:02 +02:00
|
|
|
ErrCode {
|
2020-05-25 19:11:38 +02:00
|
|
|
status_code,
|
2020-05-28 16:12:24 +02:00
|
|
|
error_name,
|
2020-05-29 16:29:46 +02:00
|
|
|
error_type: ErrorType::AuthenticationError,
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-28 16:12:24 +02:00
|
|
|
fn internal(error_name: &'static str, status_code: StatusCode) -> ErrCode {
|
2020-05-25 19:11:38 +02:00
|
|
|
ErrCode {
|
|
|
|
status_code,
|
2020-05-28 16:12:24 +02:00
|
|
|
error_name,
|
2020-05-27 12:04:35 +02:00
|
|
|
error_type: ErrorType::InternalError,
|
2020-05-25 19:11:38 +02:00
|
|
|
}
|
2020-05-22 18:04:23 +02:00
|
|
|
}
|
2020-05-19 18:13:02 +02:00
|
|
|
|
2020-05-28 16:12:24 +02:00
|
|
|
fn invalid(error_name: &'static str, status_code: StatusCode) -> ErrCode {
|
2020-05-25 19:11:38 +02:00
|
|
|
ErrCode {
|
|
|
|
status_code,
|
2020-05-28 16:12:24 +02:00
|
|
|
error_name,
|
2020-05-29 16:29:46 +02:00
|
|
|
error_type: ErrorType::InvalidRequestError,
|
2020-05-25 19:11:38 +02:00
|
|
|
}
|
2020-05-19 18:13:02 +02:00
|
|
|
}
|
|
|
|
}
|