Bandwidth & Go

Agenda

  • Why Go
  • First Revisions
  • Getting feedback
  • Rolling in feedback
  • Real world example

Why Go

Go & Communications

  • High concurrency
  • Fast
  • Low Latency
  • Strongly Typed

Concurrency

Fast

First Draft

Goals

  • Copy popular SDK Design
  • Idiomatic
  • High API Coverage

Design Patterns

// CreateMessage sends a message (SMS/MMS)
// It returns ID of created message or error
func (api *Client) CreateMessage(data interface{}) (string, error) {
  _, headers, err := api.makeRequest(http.MethodPost, api.concatUserPath(messagesPath), nil, data)
  if err != nil {
    return "", err
  }
  return getIDFromLocationHeader(headers), nil
}

Getting Feedback

To Reddit!

Feedback

...I'm a bit wary of every response being returned map[string]interface{}. Usually they're marshaled into a struct...
have exported structs that we can use and avoid map[string]interface{}.
...look at the Stripe Go SDK for examples of how you can export your API responses as a struct. look at card.go and you'll see they have a struct with types for each field and they use tags to define how it marshals/unmarshals to json. 

OK... v2.0

Design Patterns

 

// CreateMessageData struct
type CreateMessageData struct {
	From               string   `json:"from,omitempty"`
	To                 string   `json:"to,omitempty"`
	Text               string   `json:"text,omitempty"`
	Media              []string `json:"media,omitempty"`
	CallbackURL        string   `json:"callbackUrl,omitempty"`
	CallbackHTTPMethod string   `json:"callbackHttpMethod,omitempty"`
	FallbackURL        string   `json:"fallbackUrl,omitempty"`
	CallbackTimeout    int      `json:"callbackTimeout,omitempty"`
	ReceiptRequested   string   `json:"receiptRequested,omitempty"`
	Tag                string   `json:"tag,omitempty"`
}

// CreateMessage sends a message (SMS/MMS)
// It returns ID of created message or error
func (api *Client) CreateMessage(data *CreateMessageData) (string, error) {
  _, headers, err := api.makeRequest(http.MethodPost, api.concatUserPath(messagesPath), nil, data)
  if err != nil {
    return "", err
  }
  return getIDFromLocationHeader(headers), nil
}

Examples

  statuses, error := api.CreateMessages(
      &bandwidth.CreateMessageData{From: "+19195551212", To: "+191955512141", Text:"Test1"}, 
      &bandwidth.CreateMessageData{From: "+19195551212", To: "+191955512142", Text:"Test2"})
api.CreateCall(&bandwidth.CreateCallData{From: "+19195551212",  To: "+191955512142"})

Lessons Learned

  • Go != Node
  • Structs > interface
  • Reddit actually good
  • Maintainability?
  • Swagger...

Putting it all together

Updating Call

api.UpdateCall(form.CallID, &bandwidth.UpdateCallData{
    State:            "transferring",
    TransferTo:       user.SIPURI,
    TransferCallerID: callerID,
})

Order Phone Number

numbers, err := api.client.GetAndOrderAvailableNumbers(bandwidth.AvailableNumberTypeLocal,
		&bandwidth.GetAvailableNumberQuery{AreaCode: areaCode, Quantity: 1})
        if err != nil {
	    return "", err
        }
	err = api.client.UpdatePhoneNumber(numbers[0].ID,
            &bandwidth.UpdatePhoneNumberData{
                ApplicationID: applicationID
        })

github.com/bandwidthcom/go-bandwidth

github.com/BandwidthExamples/go-voice-reference-app

Questions?

Bandwidth & Go

By Daniel Tolbert

Bandwidth & Go

Slides for Go meetup in atlanta

  • 761