Skip to content

Commit

Permalink
updating sendgrid connector to have simplified inputs to work with V3…
Browse files Browse the repository at this point in the history
…-Engine
  • Loading branch information
sordina committed Sep 21, 2023
1 parent bb5f30b commit 21a5c70
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 32 deletions.
93 changes: 91 additions & 2 deletions crates/ndc-sendgrid/src/mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use serde_json::Value;
use std::collections::BTreeMap;

use crate::schema::SEND_MAIL;
use crate::sendgrid_api::{SimpleSendMailRequest, MailAddress, MailContent, MailPersonalization};

use super::configuration;
use super::schema;
Expand Down Expand Up @@ -58,13 +59,44 @@ async fn process_operation(
}
}

fn complicate_request(simple_request: SimpleSendMailRequest) -> sendgrid_api::SendMailRequest {

let personalization = MailPersonalization {
from: Some(simple_request.from.clone()),
to: vec!(simple_request.to),
cc: simple_request.cc.map(|x| vec!(x)),
bcc: simple_request.bcc.map(|x| vec!(x)),
subject: Some(simple_request.subject.clone()),
headers: None,
substitutions: None,
dynamic_template_data: None,
send_at: simple_request.send_at
};

sendgrid_api::SendMailRequest {
personalizations: vec!(personalization),
from: simple_request.from,
reply_to_list: vec!(),
subject: simple_request.subject,
content: vec!(simple_request.content),
attachments: simple_request.attachment.map(|a| vec!(a)),
template_id: simple_request.template_id,
headers: None,
send_at: simple_request.send_at,
batch_id: simple_request.batch_id,
asm: simple_request.asm
}
}

async fn process_send_mail(
http_client: &reqwest::Client,
configuration: &configuration::SendGridConfiguration,
arguments: BTreeMap<String, Value>,
fields: Option<IndexMap<String, Field>>,
) -> Result<MutationOperationResults, MutationError> {
let request = parse_send_mail_args(&arguments)?;
let simple_request = parse_simple_send_mail_args(&arguments)?;
let request = complicate_request(simple_request);

sendgrid_api::invoke_send_mail(http_client, &configuration.sendgrid_api_key, &request)
.await
.map_err(|err| MutationError::Other(Box::new(err)))?;
Expand Down Expand Up @@ -105,7 +137,64 @@ async fn process_send_mail(
})
}

fn parse_send_mail_args(
fn invalid_arg(err: &str) -> MutationError {
MutationError::InvalidRequest(format!("Couldn't find '{err}' field in arguments"))
}

fn invalid_deserialize(arg: &str, err: serde_json::Error) -> MutationError {
MutationError::InvalidRequest(format!("Unable to deserialize argument '{arg}': {err}"))
}

fn parse_simple_send_mail_args(
in_args: &BTreeMap<String, Value>,
) -> Result<sendgrid_api::SimpleSendMailRequest, MutationError> {

let args_to = in_args.get("to").ok_or(invalid_arg("request"))?;
let args_cc = in_args.get("cc");
let args_bcc = in_args.get("bcc");
let args_from = in_args.get("from").ok_or(invalid_arg("from"))?;
let args_reply_to = in_args.get("reply_to");
let args_subject = in_args.get("subject").ok_or(invalid_arg("subject"))?;
let args_content = in_args.get("content").ok_or(invalid_arg("content"))?;
let args_content_type = in_args.get("content_type").ok_or(invalid_arg("content_type"))?;
let args_attachment = in_args.get("attachment");
let args_template_id = in_args.get("template_id");
let args_send_at = in_args.get("send_at");
let args_batch_id = in_args.get("batch_id");
let args_asm = in_args.get("asm");

let to = serde_json::from_value(args_to.clone()).map_err(|err| invalid_deserialize("to", err))?;
let cc = args_cc.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("cc", err))).unwrap_or(Ok(None))?;
let bcc = args_bcc.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("bcc", err))).unwrap_or(Ok(None))?;
let from = serde_json::from_value(args_from.clone()).map_err(|err| invalid_deserialize("from", err))?;
let reply_to = args_reply_to.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("reply_to", err))).unwrap_or(Ok(None))?;
let subject = serde_json::from_value(args_subject.clone()).map_err(|err| invalid_deserialize("subject", err))?;
let content = serde_json::from_value(args_content.clone()).map_err(|err| invalid_deserialize("content", err))?;
let content_type = serde_json::from_value(args_content_type.clone()).map_err(|err| invalid_deserialize("content", err))?;
let attachment = args_attachment.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("attachment", err))).unwrap_or(Ok(None))?;
let template_id = args_template_id.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("template_id", err))).unwrap_or(Ok(None))?;
let send_at = args_send_at.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("send_at", err))).unwrap_or(Ok(None))?;
let batch_id = args_batch_id.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("batch_id", err))).unwrap_or(Ok(None))?;
let asm = args_asm.map(|x| serde_json::from_value(x.clone()).map_err(|err| invalid_deserialize("asm", err))).unwrap_or(Ok(None))?;

let request = sendgrid_api::SimpleSendMailRequest {
to: MailAddress { email: to, name: None },
cc: cc.map(|x| MailAddress { email: x, name: None }),
bcc: bcc.map(|x| MailAddress { email: x, name: None }),
from: MailAddress { email: from, name: None },
reply_to: reply_to.map(|x| MailAddress { email: x, name: None }),
subject,
content: MailContent { r#type: content_type, value: content },
attachment,
template_id,
send_at,
batch_id,
asm,
};
Ok(request)
}

fn _parse_send_mail_args(
in_args: &BTreeMap<String, Value>,
) -> Result<sendgrid_api::SendMailRequest, MutationError> {
let args_request =
Expand Down
21 changes: 0 additions & 21 deletions crates/ndc-sendgrid/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,6 @@ use super::configuration;
use super::schema::LIST_TEMPLATES_FUNCTION_NAME;
use super::sendgrid_api::{invoke_list_function_templates, ListTransactionalTemplatesParams};



// String::from("generations"),
// ArgumentInfo {
// description: Some(String::from("Comma-delimited list specifying which generations of templates to return. Options are legacy, dynamic or legacy,dynamic")),
// argument_type: nullable(named("String"))
// }),
// (
// String::from("page_size"),
// ArgumentInfo {
// description: Some(String::from("The number of templates to be returned in each page of results")),
// argument_type: named("Int")
// }),
// (
// String::from("page_token"),
// ArgumentInfo {
// description: Some(String::from("A token corresponding to a specific page of results, as provided by metadata")),
// argument_type: nullable(named("String"))
// }),


fn parse_list_templates_params(
in_args: BTreeMap<String, Argument>,
) -> Result<ListTransactionalTemplatesParams, QueryError> {
Expand Down
73 changes: 66 additions & 7 deletions crates/ndc-sendgrid/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,13 +489,72 @@ fn send_mail() -> ProcedureInfo {
ProcedureInfo {
name: String::from(SEND_MAIL),
description: Some(String::from("Allows you to send email")),
arguments: BTreeMap::from([(
String::from("request"),
ArgumentInfo {
description: Some(String::from("Request parameters")),
argument_type: named("send_mail_request"),
},
)]),
arguments: BTreeMap::from([
(String::from("from"),
ArgumentInfo {
description: Some(String::from("An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled.")),
argument_type: named("String") }),
(String::from("to"),
ArgumentInfo {
description: Some(String::from("An address that will be sent the email.")),
argument_type: named("String") }),
(String::from("cc"),
ArgumentInfo {
description: Some(String::from("An address that will be cced the email.")),
argument_type: nullable(named("String")) }),
(String::from("bcc"),
ArgumentInfo {
description: Some(String::from("An address that will be bcced the email.")),
argument_type: nullable(named("String")) }),
(String::from("reply_to"),
ArgumentInfo {
description: Some(String::from("An array of recipients who will receive replies.")),
argument_type: nullable(named("String")) }),
(String::from("subject"),
ArgumentInfo {
description: Some(String::from("The subject of your email. See character length requirements according to RFC 2822.")),
argument_type: named("String") }),
// (String::from("content"),
// ArgumentInfo {
// description: Some(String::from("An array where you can specify the content of your email. You can include multiple MIME types of content, but you must specify at least one MIME type.")),
// argument_type: named("mail_content") }),
(String::from("content_type"),
ArgumentInfo {
description: Some(String::from("The MIME type of the content you are including in your email")),
argument_type: named("String") }),
(String::from("content"),
ArgumentInfo {
description: Some(String::from("The actual content of the specified MIME type that you are including in your email.")),
argument_type: named("String") }),
// (String::from("type"), ObjectField {
// r#type: named("String"),
// description: Some(String::from("The MIME type of the content you are including in your email"))
// }),
// (String::from("name"), ObjectField {
// r#type: named("String"),
// description: Some(String::from("The actual content of the specified MIME type that you are including in your email."))
// }),
// (String::from("attachment"),
// ArgumentInfo {
// description: Some(String::from("An object where you can specify an attachment you want to include.")),
// argument_type: nullable(named("mail_attachment")) }),
(String::from("template_id"),
ArgumentInfo {
description: Some(String::from("An email template ID. A template that contains a subject and content — either text or html — will override any subject and content values specified at the personalizations or message level.")),
argument_type: nullable(named("String")) }),
(String::from("send_at"),
ArgumentInfo {
description: Some(String::from("A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the send_at parameter set at the personalizations level. Delivery cannot be scheduled more than 72 hours in advance.")),
argument_type: nullable(named("Int")) }),
(String::from("batch_id"),
ArgumentInfo {
description: Some(String::from("An ID representing a batch of emails to be sent at the same time. Including a batch_id in your request allows you include this email in that batch. It also enables you to cancel or pause the delivery of that batch.")),
argument_type: nullable(named("String")) }) //,
// (String::from("asm"),
// ArgumentInfo {
// description: Some(String::from("An object allowing you to specify how to handle unsubscribes.")),
// argument_type: nullable(named("unsubscription_settings")) })
]),
result_type: named("send_mail_response"),
}
}
Expand Down
20 changes: 18 additions & 2 deletions crates/ndc-sendgrid/src/sendgrid_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ impl Display for ErrorResponse {
#[derive(Deserialize, Clone, Debug)]
pub struct ErrorItem {
pub message: String,
pub error_id: String,
pub field: String,
}

impl Display for ErrorItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.error_id, self.message)
write!(f, "{}: {}", self.field, self.message)
}
}

Expand All @@ -120,6 +120,22 @@ pub enum RequestError<Err> {
OtherError { error: String },
}

#[derive(Serialize, Clone, Debug)]
pub struct SimpleSendMailRequest {
pub from: MailAddress,
pub to: MailAddress,
pub cc: Option<MailAddress>,
pub bcc: Option<MailAddress>,
pub reply_to: Option<MailAddress>,
pub subject: String,
pub content: MailContent,
pub attachment: Option<MailAttachment>,
pub template_id: Option<String>,
pub send_at: Option<u32>,
pub batch_id: Option<String>,
pub asm: Option<UnsubscriptionSettings>,
}

#[derive(Serialize, Clone, Debug)]
pub struct SendMailRequest {
pub personalizations: Vec<MailPersonalization>,
Expand Down

0 comments on commit 21a5c70

Please sign in to comment.