3

I'm trying to send a request to the SendGrid API using Swift 4 and URLSession. My hope is to not include any third-party dependencies since this is the only place in my app where I use JSON and an HTTP request.

Since SendGrid doesn't have any Swift examples, I'm looking at the cURL sample:

curl --request POST \
--url https://api.sendgrid.com/v3/mail/send \
--header "Authorization: Bearer $SENDGRID_API_KEY" \
--header 'Content-Type: application/json' \
--data '{"personalizations": [{"to": [{"email": "test@example.com"}]}],"from": {"email": "test@example.com"},"subject": "Sending with SendGrid is Fun","content": [{"type": "text/plain", "value": "and easy to do anywhere, even with cURL"}]}'

I think I have everything arranged except I'm unsure how to encode the data portion into valid JSON for the request. I tried converting it to a Dictionary, but it doesn't work. Here's my code:

let sendGridURL = "https://api.sendgrid.com/v3/mail/send"

var request = URLRequest(url: URL(string: sendGridURL)!)
request.httpMethod = "POST"

//Headers
request.addValue("Bearer \(sendGridAPIKey)", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")

//Data
let json = [
    "personalizations":[
    "to": ["email":"test@example.com"],
    "from": ["email":"test@example.com"],
    "subject": "Sending with SendGrid is Fun",
    "content":["type":"text/plain", "value":"and easy to do anywhere, even with Swift"]
    ]
]

let data = try! JSONSerialization.data(withJSONObject: json, options: [])
let ready = try! JSONEncoder().encode(data) <-- !!! Crash !!!

request.httpBody = ready

Has anyone pulled this same thing off from a Swift app that can help me out?

Update

For anyone trying to do the same thing, I had to adjust my JSON to look like this in order for it to be formatted correctly for SendGrid:

let json:[String:Any] = [
    "personalizations":[["to": [["email":"test@example.com"]]]],
      "from": ["email":"test@example.com"],
      "subject": "Sending with SendGrid is Fun",
      "content":[["type":"text/plain", "value":"and easy to do anywhere, even with Swift"]]
  ]
Clifton Labrum
  • 13,053
  • 9
  • 65
  • 128

1 Answers1

4

There's no need to encode the JSON data twice. Remove this line

let ready = try! JSONEncoder().encode(data) // <-- !!! Crash !!!

and simply do

do {
  let data = try JSONSerialization.data(withJSONObject: json, options: [])
  request.httpBody = data
} catch {
   print("\(error)")
}

Also, don't use try! if you can avoid it.

Gereon
  • 17,258
  • 4
  • 42
  • 73
  • Thanks for your help! – Clifton Labrum Jun 11 '18 at 16:50
  • It looks like my JSON is okay now, but I keep getting a 400 error (bad request). – Clifton Labrum Jun 11 '18 at 17:15
  • 1
    Never mind, I posted an update in my question that fixes it. – Clifton Labrum Jun 11 '18 at 17:51
  • Sendgrid states "All responses are returned in JSON format. We specify this by sending the Content-Type header." However, I'm seeing text/plain instead. The response also includes this link: https://sendgrid.com/docs/Classroom/Basics/API/cors.html Does that mean there was a problem? The send worked - I received the email at the intended destination. – Victor Engel Oct 16 '21 at 18:11