lemon_bugsnag_rs 0.1.2

A library for interacting with the BugSnag error-reporting and sessions APIs.
Documentation
use super::client_trait_async::ClientTraitAsync;
use std::error::Error;

/// Trait to be implemented by builders specific to various backend providers,
/// such as Reqwest and Ureq. See
/// [ClientBuilderReqwestErrorAsync](
///     crate::error::reqwest::builder::non_blocking::ClientBuilderReqwestErrorAsync
/// ).
/// [ClientBuilderReqwestSessionAsync](
///     crate::session::reqwest::builder::non_blocking::ClientBuilderReqwestSessionAsync
/// ).
///
/// # Example
/// ```
/// // This example requires the session-client feature.
///
/// use lemon_bugsnag_rs::common::traits::backend_builder_trait_async::BackendBuilderTraitAsync;
/// use lemon_bugsnag_rs::common::traits::client_trait_async::ClientTraitAsync;
/// use lemon_bugsnag_rs::common::error::Error as NabBugsnagRsError;
/// use lemon_bugsnag_rs::session::reqwest::client::non_blocking::ReqwestSessionAsync;
///
/// struct MyAsyncSessionClientBuilder {}
/// struct MyAsyncSessionClient {}
/// #[async_trait::async_trait]
/// impl ClientTraitAsync for MyAsyncSessionClient {
///   // In production code, you would want to use the response type
///   // provided by your backend library. In this case, that would
///   // be ureq::Response;
///   type Response = ();
///   type Error = NabBugsnagRsError;
///
///   async fn send(&mut self) -> Result<Self::Response, Self::Error> {
///     // In real code, this would be the successful response type
///     // returned by your back-end library, as specified when you
///     // implemented ClientTraitAsync.
///     Ok(())
///   }
/// }
///
/// impl BackendBuilderTraitAsync<
///   MyAsyncSessionClient
///   , NabBugsnagRsError
/// > for MyAsyncSessionClientBuilder {
///     fn build(self) -> Result<MyAsyncSessionClient, NabBugsnagRsError> {
///         Ok(MyAsyncSessionClient {})
///         // Alternatively, in case of error:
///         // Err(NabBugsnagRsError {})
///     }
/// }
/// ```
pub trait BackendBuilderTraitAsync<T, E>
where
    E: Error,
    T: ClientTraitAsync,
{
    /// Returns T on success, E on error, where T is a fully configured and
    /// functional client ready to send its payload.
    ///
    /// # Example
    /// ```
    /// // This example requires the ureq feature.
    /// // This example requires the optional-builders feature.
    ///
    /// use lemon_bugsnag_rs::common::error::ErrorStack;
    /// # #[cfg(norun)]
    /// use lemon_bugsnag_rs::session::payload::{Payload, App, notifier::Notifier, device::Device};
    /// # use lemon_bugsnag_rs::session::payload::{App, notifier::Notifier, device::Device};
    /// use lemon_bugsnag_rs::common::traits::backend_builder_trait_async::BackendBuilderTraitAsync;
    /// use ureq::{AgentBuilder, Response};
    ///
    /// # use lemon_bugsnag_rs::session::payload::{
    /// #     
    /// #     sessions::Session,
    /// #     session_counts::session_count::SessionCount
    /// # };
    /// # #[derive(Clone, Debug, serde::Serialize)]
    /// # struct Payload {
    /// #     pub notifier: Notifier,
    /// #     pub app: Option<App>,
    /// #     pub device: Option<Device>,
    /// #     pub sessions: Option<Vec<Session>>,
    /// #     pub session_counts: Option<Vec<SessionCount>>,
    /// # }
    ///
    /// # use lemon_bugsnag_rs::common::error::Error;
    /// # use lemon_bugsnag_rs::common::traits::client_trait_async::ClientTraitAsync;
    /// # use ureq::Request;
    /// # struct MyClientBuilder {}
    /// # struct MyClient {
    /// #     pub url: url::Url,
    /// #     pub request: Request,
    /// #     pub (crate) payload: Payload        
    /// # }
    /// #
    /// #[async_trait::async_trait]
    /// impl ClientTraitAsync for MyClient {
    /// #   #[cfg(norun)]
    ///     type Response = Response;
    /// #   type Response = ();
    ///     type Error = Error;
    ///
    /// #     #[cfg(norun)]
    ///      async fn send(&mut self) -> Result<Self::Response, Self::Error> {
    ///          // This is roughly how this crate implements send() for the Ureq
    ///          // backend. Your own implementation may look nothing like this.
    ///          Ok(self.request.clone().send_json(self.payload.clone())?)
    ///      }
    ///
    /// #     async fn send(&mut self) -> Result<(), Self::Error> {
    /// #         Ok(())
    /// #     }
    /// }
    ///
    /// impl BackendBuilderTraitAsync<MyClient, ErrorStack> for MyClientBuilder {
    ///     fn build(self) -> Result<MyClient, ErrorStack> {
    ///       let request = AgentBuilder::new()
    ///         .build()
    ///         .post("https://appropriate.api.host/endpoint");
    ///       let url = url::Url::parse("https://api.bugsnag.com/").unwrap();
    ///       let payload = Payload {
    ///         notifier: Notifier::builder()
    ///             .set_name("My session notifier")
    ///             .set_version("1.0")
    ///             .build()
    ///             // Production code should handle potential unwrap() panics.
    ///             .unwrap(),
    ///         // Fill out the payload as appropriate for your use case.
    ///         // Most optional fields have been set to None in this example
    ///         // for simplicity.
    ///         app: App::builder()
    ///             .set_app_type("Rust application")
    ///             .set_release_stage("development")
    ///             .build()
    ///             .into(),
    ///         device: None,
    ///         sessions: None,
    ///         session_counts: None,
    ///       };
    ///
    ///     /*
    ///     In case of errors, build and return an ErrorStack as specified in
    ///     the trait implementation. The ErrorStack is appropriate when the
    ///     build() function might generate more than one type of error in a
    ///     single call, as shown in the example below. In other cases, this
    ///     crate's Error struct is generally the correct choice.
    ///
    ///     let mut error_stack = ErrorStack::default();
    ///     let mut missing_fields: Vec<String> = Vec::new();
    ///     let mut conflicting_fields: Vec<String> = Vec::new();
    ///     missing_fields.push("some_required_field");
    ///     error_stack.errors.push(
    ///        BuilderError::MissingField(
    ///            context: "MyClientBuilder::build()".to_string(),
    ///            fields: missing_fields
    ///        )
    ///        .into()
    ///     );
    ///     // You cannot specify both of these for a single Sessions payload.
    ///     conflicting_fields.push("sessions".to_string());
    ///     conflicting_fields.push("session_counts".to_string());
    ///     error_stack.errors.push(
    ///         BuilderError::ConflictingField{
    ///             context: "MyClientBuilder::build()".to_string(),
    ///             fields: conflicting_fields,
    ///         }
    ///         .into(),
    ///     );
    ///     */
    ///
    ///       Ok(MyClient {
    ///           url,
    ///           request,
    ///           payload
    ///       })
    ///    }
    /// }
    /// ```
    fn build(self) -> Result<T, E>;
}