Skip to content

Commit 877ab9a

Browse files
committed
Modify AddContacts to use PUT requests rather than the alternative GET method.
On August 21st, a PR was merged into Go's master (https://go-review.googlesource.com/c/go/+/99135). That PR forces url.URL queries to actually be properly encoded, which breaks our previous implementation.
1 parent f9fb708 commit 877ab9a

File tree

3 files changed

+47
-28
lines changed

3 files changed

+47
-28
lines changed

client.go

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ type Client struct {
4747
DebugLog *log.Logger // Optional logger for debugging purposes
4848
}
4949

50+
type contentType string
51+
52+
const (
53+
contentTypeEmpty contentType = ""
54+
contentTypeJSON contentType = "application/json"
55+
contentTypeFormURLEncoded contentType = "application/x-www-form-urlencoded"
56+
)
57+
5058
// New creates a new MessageBird client object.
5159
func New(accessKey string) *Client {
5260
return &Client{
@@ -67,27 +75,24 @@ func (c *Client) Request(v interface{}, method, path string, data interface{}) e
6775
return err
6876
}
6977

70-
var jsonEncoded []byte
71-
if data != nil {
72-
jsonEncoded, err = json.Marshal(data)
73-
if err != nil {
74-
return err
75-
}
78+
body, contentType, err := prepareRequestBody(data)
79+
if err != nil {
80+
return err
7681
}
7782

78-
request, err := http.NewRequest(method, uri.String(), bytes.NewBuffer(jsonEncoded))
83+
request, err := http.NewRequest(method, uri.String(), bytes.NewBuffer(body))
7984
if err != nil {
8085
return err
8186
}
8287

83-
request.Header.Set("Content-Type", "application/json")
88+
request.Header.Set("Content-Type", string(contentType))
8489
request.Header.Set("Accept", "application/json")
8590
request.Header.Set("Authorization", "AccessKey "+c.AccessKey)
8691
request.Header.Set("User-Agent", "MessageBird/ApiClient/"+ClientVersion+" Go/"+runtime.Version())
8792

8893
if c.DebugLog != nil {
8994
if data != nil {
90-
c.DebugLog.Printf("HTTP REQUEST: %s %s %s", method, uri.String(), jsonEncoded)
95+
c.DebugLog.Printf("HTTP REQUEST: %s %s %s", method, uri.String(), body)
9196
} else {
9297
c.DebugLog.Printf("HTTP REQUEST: %s %s", method, uri.String())
9398
}
@@ -136,3 +141,24 @@ func (c *Client) Request(v interface{}, method, path string, data interface{}) e
136141
return errorResponse
137142
}
138143
}
144+
145+
// prepareRequestBody takes untyped data and attempts constructing a meaningful
146+
// request body from it. It also returns the appropriate Content-Type.
147+
func prepareRequestBody(data interface{}) ([]byte, contentType, error) {
148+
// Nil bodies are accepted by `net/http`, so this is not an error.
149+
if data == nil {
150+
return nil, contentTypeEmpty, nil
151+
}
152+
153+
s, ok := data.(string)
154+
if ok {
155+
return []byte(s), contentTypeFormURLEncoded, nil
156+
}
157+
158+
b, err := json.Marshal(data)
159+
if err != nil {
160+
return nil, contentType(""), err
161+
}
162+
163+
return b, contentTypeJSON, nil
164+
}

group/group.go

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,9 @@ func AddContacts(c *messagebird.Client, groupID string, contactIDs []string) err
161161
return err
162162
}
163163

164-
query := addContactsQuery(contactIDs)
165-
formattedPath := fmt.Sprintf("%s/%s/%s?%s", path, groupID, contactPath, query)
164+
data := addContactsData(contactIDs)
166165

167-
return c.Request(nil, http.MethodGet, formattedPath, nil)
166+
return c.Request(nil, http.MethodPut, path+"/"+groupID+"/"+contactPath, data)
168167
}
169168

170169
func validateAddContacts(contactIDs []string) error {
@@ -182,19 +181,12 @@ func validateAddContacts(contactIDs []string) error {
182181
return nil
183182
}
184183

185-
// addContactsQuery gets a query string to add contacts to a group. We're using
186-
// the alternative "/foo?_method=PUT&key=value" format to send the contact IDs
187-
// as GET params. Sending these in the request body would require a painful
188-
// workaround, as client.Request sends request bodies as JSON by default. See
189-
// also: https://developers.messagebird.com/docs/alternatives.
190-
//
191-
// It should also be noted that we're intentionally not using url.Values for
192-
// building the query string: the API expects `ids[]=foo&ids[]=bar` format,
193-
// while url.Values encodes to `ids=foo&ids=bar`.
194-
func addContactsQuery(contactIDs []string) string {
195-
// Slice's length is one bigger than len(IDs) for the _method param.
196-
params := make([]string, 0, len(contactIDs)+1)
197-
params = append(params, "_method="+http.MethodPut)
184+
// addContactsData gets the data string for adding a contact to a group. We're
185+
// intentionally not using url.Values for building the string: the API expects
186+
// `ids[]=foo&ids[]=bar` format, while url.Values encodes to `ids=foo&ids=bar`.
187+
func addContactsData(contactIDs []string) string {
188+
cap := len(contactIDs)
189+
params := make([]string, 0, cap)
198190

199191
for _, contactID := range contactIDs {
200192
params = append(params, "ids[]="+contactID)

group/group_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,11 @@ func TestAddContacts(t *testing.T) {
169169
t.Fatalf("unexpected error removing Contacts from Group: %s", err)
170170
}
171171

172-
mbtest.AssertEndpointCalled(t, http.MethodGet, "/groups/group-id/contacts")
172+
mbtest.AssertEndpointCalled(t, http.MethodPut, "/groups/group-id/contacts")
173+
mbtest.AssertTestdata(t, "groupRequestAddContactsObject.txt", mbtest.Request.Body)
173174

174-
if mbtest.Request.URL.RawQuery != "_method=PUT&ids[]=first-contact-id&ids[]=second-contact-id" {
175-
t.Fatalf("got %s, expected _method=PUT&ids[]=first-contact-id&ids[]=second-contact-id", mbtest.Request.URL.RawQuery)
175+
if mbtest.Request.ContentType != "application/x-www-form-urlencoded" {
176+
t.Fatalf("got %s, expected application/x-www-form-urlencoded", mbtest.Request.ContentType)
176177
}
177178
}
178179

0 commit comments

Comments
 (0)