postmark 2.0.1

Postmark rust client
Documentation
use crate::{
    Endpoint,
    api::{Body, endpoint_with_path_segment},
};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use typed_builder::TypedBuilder;

use super::*;

/// Get an e-mail template. The template may be specified by its template id or alias
/// using the [`TemplateIdOrAlias`] enumeration.
///
/// ```
/// use postmark::api::{Body, templates::{GetTemplateRequest, TemplateIdOrAlias}};
/// let req = GetTemplateRequest::builder()
///   .id(TemplateIdOrAlias::TemplateId(12345.into()))
///   .build();
/// ```
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
#[derive(TypedBuilder)]
pub struct GetTemplateRequest {
    /// ID of template or template alias
    #[builder(setter(into))]
    pub id: TemplateIdOrAlias,
}

/// Response for the [`GetTemplateRequest`] Endpoint.
///
/// On success (2XX HTML code response), all information for the template
/// is returned.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct GetTemplateResponse {
    /// ID of template
    pub template_id: TemplateId,
    /// Name of template
    pub name: String,
    /// The content to use for the Subject when this template is used to send email.
    pub subject: String,
    /// The content to use for the HtmlBody and/or TextBody when this template is
    /// used to send email.
    #[serde(flatten)]
    pub body: Body,
    /// The ID of the Server with which this template is associated.
    pub associated_server_id: crate::api::server::ServerId,
    /// Indicates that this template may be used for sending email.
    pub active: bool,
    /// Template alias (or None if not specified).
    pub alias: Option<String>,
    /// Type of template. Possible options: Standard or Layout.
    pub template_type: TemplateType,
    /// Alias of layout used.
    pub layout_template: Option<String>,
}

impl Endpoint for GetTemplateRequest {
    type Request = GetTemplateRequest;
    type Response = GetTemplateResponse;

    fn endpoint(&self) -> Cow<'static, str> {
        endpoint_with_path_segment("/templates", &self.id.to_string())
    }

    fn body(&self) -> &Self::Request {
        self
    }

    fn method(&self) -> http::Method {
        http::Method::GET
    }
}

#[cfg(test)]
mod tests {
    use httptest::matchers::request;
    use httptest::{Expectation, Server, responders::*};
    use serde_json::json;

    use super::*;
    use crate::Query;
    use crate::reqwest::PostmarkClient;

    const NAME: &str = "Onboarding Email";
    const ALIAS: &str = "my-template-alias";
    const TEXT_BODY: &str = "Welcome, {{name}}, you are a Postmark user.";
    const HTML_BODY: &str =
        "<html><body><strong>Welcome</strong>, {{name}}, you are a Postmark user.</body></html>";
    const SUBJ: &str = "Welcome to Postmark!";
    const LAYOUT_TEMPL: &str = "my-layout";

    #[tokio::test]
    pub async fn get_template_test_by_template_id() {
        let server = Server::run();

        server.expect(
            Expectation::matching(request::method_path("GET", "/templates/12345")).respond_with(
                json_encoded(json!({
                    "TemplateId": 12345,
                    "Name": NAME,
                    "Subject": SUBJ,
                    "HtmlBody": HTML_BODY,
                    "TextBody": TEXT_BODY,
                    "AssociatedServerId": 67890,
                    "Active": true,
                    "Alias": ALIAS,
                    "TemplateType": "Standard",
                    "LayoutTemplate": LAYOUT_TEMPL,
                })),
            ),
        );

        let client = PostmarkClient::builder()
            .base_url(server.url("/").to_string())
            .build();

        let req = GetTemplateRequest::builder()
            .id(TemplateIdOrAlias::TemplateId(12345.into()))
            .build();

        req.execute(&client)
            .await
            .expect("Should get a response and be able to json decode it");
    }

    #[tokio::test]
    pub async fn get_template_test_by_alias() {
        let server = Server::run();

        server.expect(
            Expectation::matching(request::method_path("GET", "/templates/my-template-alias"))
                .respond_with(json_encoded(json!({
                    "TemplateId": 12345,
                    "Name": NAME,
                    "Subject": SUBJ,
                    "HtmlBody": HTML_BODY,
                    "TextBody": TEXT_BODY,
                    "AssociatedServerId": 67890,
                    "Active": true,
                    "Alias": ALIAS,
                    "TemplateType": "Standard",
                    "LayoutTemplate": LAYOUT_TEMPL,
                }))),
        );

        let client = PostmarkClient::builder()
            .base_url(server.url("/").to_string())
            .build();

        let req = GetTemplateRequest::builder()
            .id(TemplateIdOrAlias::Alias(String::from(ALIAS)))
            .build();

        req.execute(&client)
            .await
            .expect("Should get a response and be able to json decode it");
    }

    #[test]
    fn get_template_encodes_alias_path_segment() {
        let req = GetTemplateRequest::builder()
            .id(TemplateIdOrAlias::Alias(
                "folder/name with space".to_string(),
            ))
            .build();

        assert_eq!(
            req.endpoint().as_ref(),
            "/templates/folder%2Fname%20with%20space"
        );
    }
}