bonsaidb_core/
api.rs

1use std::fmt::{Debug, Display};
2use std::ops::Deref;
3
4pub use bonsaidb_macros::Api;
5use serde::{Deserialize, Serialize};
6
7use 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/// ```
44pub 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")]
61pub enum Infallible {}
62
63/// An error that can be used within a [`Api`] definition.
64pub trait ApiError:
65    std::fmt::Display + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + Debug
66{
67}
68
69impl<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.
75pub 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#[derive(Hash, PartialEq, Eq, Deserialize, Serialize, Debug, Clone, Ord, PartialOrd)]
79#[serde(transparent)]
80pub struct ApiName(QualifiedName);
81
82impl Qualified for ApiName {
83    fn new<A: Into<Authority>, N: Into<Name>>(authority: A, name: N) -> Self {
84        Self(QualifiedName::new(authority, name))
85    }
86}
87
88impl Display for ApiName {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        Display::fmt(&self.0, f)
91    }
92}
93
94impl Deref for ApiName {
95    type Target = QualifiedName;
96
97    fn deref(&self) -> &Self::Target {
98        &self.0
99    }
100}