Posting data

Posting data to a web service should be just as easy as changing a Get() function call to a Post() but there are often complications. Consider our email example and the task of connecting to Gmail. The API is straightforward and we can easily make the request, but the data must be appropriately formatted. Emails have complex encodings when sent to mail servers and we need to implement that to work with the API. The Gmail service requires an RFC 2822 encoded email (which the Go standard library doesn't provide), which is then base64url encoded (the standard library can handle this). Before we can post any email messages, we need to add an encoder to our EmailMessage type, as follows:

func (e *EmailMessage) ToGMailEncoding() string {
m := mime.NewMultipartMessage("alternative", "")
m.SetHeader("Subject", mime.EncodeWord(e.Subject))
m.SetHeader("From", mime.EncodeWord("Demo") + " <" + string(e.From) + ">")
m.SetHeader("To", mime.EncodeWord("Demo") + " <" + string(e.To) + ">")
plain := mime.NewTextMessage(qprintable.UnixTextEncoding, bytes.NewBufferString(e.Content))
plain.SetHeader("Content-Type", "text/plain")
m.AddPart(plain)

var buf bytes.Buffer
io.Copy(&buf, m)
return base64.URLEncoding.EncodeToString(buf.Bytes())
}

This code makes use of an external library, github.com/sloonz/go-mime-message, and it has been imported as mime for convenience. We're using the name Demo as we haven't recorded people's names in these examples; you could omit that part if you prefer. To implement the sending of emails, we can check the Google documentation at https://developers.google.com/gmail/api/v1/reference/users/messages/send to find out that we need to pass a JSON payload with the encoded data as a value associated with the raw key. A simple method should be able to package that and send it to the API:

func postMessage(msg *EmailMessage) {
raw := msg.ToGMailEncoding()
body := fmt.Sprintf("{"raw": "%s"}", raw)

ret := authPost("https://www.googleapis.com/gmail/v1/users/me/messages/send",
"application/json", strings.NewReader(body))
io.Copy(os.Stdout, ret)
ret.Close()
}

For this code, we need just one more function, authPost(). This function will make an authenticated post to our URL passing the content type and request body as the second and third parameters. This method could save the URL, content type, and payload to re-submit if the authorization workflow is required, but often this is unwise or impossible for an HTTP post request and so we simply re-use the token that was generated in the previous authStream() function. If you do reuse this token, then you'll need to remember to update the code to request additional permissions; the updated scope should be as follows:

   Scopes: []string{"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.compose"},

With this changed, a new token is issued and, with the preceding code in place, we can execute a simple method to send an email using the postMessage() function listed previously:

func main() {
setupOAuth()
token = loadToken()

msg := &EmailMessage{
"GoMail Test Email",
"This is a test email sent from a Go example",
"[email protected]",
"[email protected]",
time.Now()}
postMessage(msg)
}

The preceding postMessage() function outputs useful debug information, but that can clearly be switched off and the email can send handle failures in a more appropriate manner:

The debug from our email post example; Gmail returns the message and thread ID along with label information
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.31.67