1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use http::StatusCode;
use serde::Serialize;
use thiserror::Error;

use htsget_search::htsget::HtsGetError as HtsGetSearchError;

pub type Result<T> = core::result::Result<T, HtsGetError>;

/// An error type that describes the errors specified in the
/// [HtsGet specification](https://samtools.github.io/hts-specs/htsget.html)
#[derive(Error, Debug, PartialEq, Eq)]
pub enum HtsGetError {
  #[error("InvalidAuthentication")]
  InvalidAuthentication(String),
  #[error("PermissionDenied")]
  PermissionDenied(String),
  #[error("NotFound")]
  NotFound(String),
  #[error("PayloadTooLarge")]
  PayloadTooLarge(String),
  #[error("UnsupportedFormat")]
  UnsupportedFormat(String),
  #[error("InvalidInput")]
  InvalidInput(String),
  #[error("InvalidRange")]
  InvalidRange(String),
  #[error("InternalError")]
  InternalError(String),
}

/// A helper struct implementing [serde's Serialize trait](Serialize) to allow
/// easily converting HtsGetErrors to JSON
#[derive(Serialize)]
pub struct JsonHtsGetError {
  error: String,
  message: String,
}

/// The "htsget" container wrapping the actual error response above
#[derive(Serialize)]
pub struct WrappedHtsGetError {
  htsget: JsonHtsGetError,
}

impl HtsGetError {
  /// Allows converting the error to JSON and the correspondent
  /// status code
  pub fn to_json_representation(&self) -> (WrappedHtsGetError, StatusCode) {
    let (err, status_code) = match self {
      HtsGetError::InvalidAuthentication(err) => (err, StatusCode::UNAUTHORIZED),
      HtsGetError::PermissionDenied(err) => (err, StatusCode::FORBIDDEN),
      HtsGetError::NotFound(err) => (err, StatusCode::NOT_FOUND),
      HtsGetError::PayloadTooLarge(err) => (err, StatusCode::PAYLOAD_TOO_LARGE),
      HtsGetError::UnsupportedFormat(err)
      | HtsGetError::InvalidInput(err)
      | HtsGetError::InvalidRange(err) => (err, StatusCode::BAD_REQUEST),
      HtsGetError::InternalError(err) => (err, StatusCode::INTERNAL_SERVER_ERROR),
    };

    (
      WrappedHtsGetError {
        htsget: JsonHtsGetError {
          error: self.to_string(),
          message: err.to_string(),
        },
      },
      status_code,
    )
  }
}

impl From<HtsGetSearchError> for HtsGetError {
  fn from(error: HtsGetSearchError) -> Self {
    match error {
      HtsGetSearchError::NotFound(err) => Self::NotFound(err),
      HtsGetSearchError::UnsupportedFormat(err) => Self::UnsupportedFormat(err),
      HtsGetSearchError::InvalidInput(err) => Self::InvalidInput(err),
      HtsGetSearchError::InvalidRange(err) => Self::InvalidRange(err),
      HtsGetSearchError::IoError(err) | HtsGetSearchError::ParseError(err) => Self::NotFound(err),
      HtsGetSearchError::InternalError(err) => Self::InternalError(err),
    }
  }
}