1
use std::fmt::{Debug, Display};
2
use std::ops::Deref;
3

            
4
pub use bonsaidb_macros::Api;
5
use serde::{Deserialize, Serialize};
6

            
7
use crate::schema::{Authority, Name, Qualified, QualifiedName};
8

            
9
/// An API request type. This trait is used by BonsaiDb's server to allow a
10
/// client to send a request of this type, and the server can respond with a
11
/// `Result<`[`Api::Response`]`,`[`Api::Error`]`>`.
12
///
13
/// # Deriving this trait
14
///
15
/// This trait can be derived. The only required attribute is `name`:
16
///
17
/// - `name = "api-name"` or `name = "api-name", authority = "api-authority"`:
18
///   Configures the Api's fully qualified name. This name must be unique across
19
///   all other Apis installed. When creating an Api that is meant to be reused,
20
///   ensure that a unique authority is used to prevent name collisions.
21
/// - `response = ResponseType`: Configures the [`Api::Response`] associated
22
///   type. This is the type that the handler will return upon success. If not
23
///   specified, `()` is used.
24
/// - `error = ErrorType`: Configures the [`Api::Error`] associated type. This
25
///   is the type that the handler will return upon error. If not specified,
26
///   [`Infallible`] is used.
27
///
28
/// ```rust
29
/// use bonsaidb_core::api::Api;
30
/// use serde::{Deserialize, Serialize};
31
///
32
/// #[derive(Api, Debug, Serialize, Deserialize)]
33
/// #[api(name = "list-records", response = Vec<Record>)]
34
/// # #[api(core = bonsaidb_core)]
35
/// struct ListRecords {
36
///     starting_id: u64,
37
/// }
38
///
39
/// #[derive(Debug, Serialize, Deserialize, Clone)]
40
/// struct Record {
41
///     title: String,
42
/// }
43
/// ```
44
pub trait Api: Serialize + for<'de> Deserialize<'de> + Send + Sync + Debug + 'static {
45
    /// The type that represents an API response. This type will be sent to clients from the server.
46
    type Response: Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + Debug;
47
    /// The error type that this  can return.
48
    type Error: ApiError;
49

            
50
    /// Returns the unique name of this api.
51
    fn name() -> ApiName;
52
}
53
/// An Error type that can be used in within an [`Api`] definition.
54
///
55
/// The reason `std::convert::Infallible` can't be used is because `Api`
56
/// errors must be able to be serialized across a network connection. While a
57
/// value will never be present when this is Infallible, the associated type
58
/// still must be declared as Serializable.
59
#[derive(thiserror::Error, Debug, Clone, Serialize, Deserialize)]
60
#[error("an unreachable error")]
61
pub enum Infallible {}
62

            
63
/// An error that can be used within a [`Api`] definition.
64
pub trait ApiError:
65
    std::fmt::Display + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + Debug
66
{
67
}
68

            
69
impl<T> ApiError for T where
70
    T: std::fmt::Display + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + Debug
71
{
72
}
73

            
74
/// The result of executing a custom API call.
75
pub type ApiResult<Api> = Result<<Api as self::Api>::Response, <Api as self::Api>::Error>;
76

            
77
/// The qualified name of an [`Api`](crate::api::Api).
78
5217714
#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
79
#[serde(transparent)]
80
pub struct ApiName(QualifiedName);
81

            
82
impl Qualified for ApiName {
83
3033825
    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self {
84
3033825
        Self(QualifiedName::new(authority, name))
85
3033825
    }
86
}
87

            
88
impl Display for ApiName {
89
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90
        Display::fmt(&self.0, f)
91
    }
92
}
93

            
94
impl Deref for ApiName {
95
    type Target = QualifiedName;
96

            
97
    fn deref(&self) -> &Self::Target {
98
        &self.0
99
    }
100
}