Skip to content

Commit 29552d9

Browse files
author
Artur Khabibullin
authored
Merge pull request #50 from messagebird/fix-query
Fix query
2 parents af55326 + 576bbf8 commit 29552d9

File tree

5 files changed

+59
-34
lines changed

5 files changed

+59
-34
lines changed

client.go

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
const (
2727
// ClientVersion is used in User-Agent request header to provide server with API level.
28-
ClientVersion = "5.1.0"
28+
ClientVersion = "5.1.1"
2929

3030
// Endpoint points you to MessageBird REST API.
3131
Endpoint = "https://rest.messagebird.com"
@@ -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,26 @@ 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")
8488
request.Header.Set("Accept", "application/json")
8589
request.Header.Set("Authorization", "AccessKey "+c.AccessKey)
8690
request.Header.Set("User-Agent", "MessageBird/ApiClient/"+ClientVersion+" Go/"+runtime.Version())
91+
if contentType != contentTypeEmpty {
92+
request.Header.Set("Content-Type", string(contentType))
93+
}
8794

8895
if c.DebugLog != nil {
8996
if data != nil {
90-
c.DebugLog.Printf("HTTP REQUEST: %s %s %s", method, uri.String(), jsonEncoded)
97+
c.DebugLog.Printf("HTTP REQUEST: %s %s %s", method, uri.String(), body)
9198
} else {
9299
c.DebugLog.Printf("HTTP REQUEST: %s %s", method, uri.String())
93100
}
@@ -136,3 +143,22 @@ func (c *Client) Request(v interface{}, method, path string, data interface{}) e
136143
return errorResponse
137144
}
138145
}
146+
147+
// prepareRequestBody takes untyped data and attempts constructing a meaningful
148+
// request body from it. It also returns the appropriate Content-Type.
149+
func prepareRequestBody(data interface{}) ([]byte, contentType, error) {
150+
switch data := data.(type) {
151+
case nil:
152+
// Nil bodies are accepted by `net/http`, so this is not an error.
153+
return nil, contentTypeEmpty, nil
154+
case string:
155+
return []byte(data), contentTypeFormURLEncoded, nil
156+
default:
157+
b, err := json.Marshal(data)
158+
if err != nil {
159+
return nil, contentType(""), err
160+
}
161+
162+
return b, contentTypeJSON, nil
163+
}
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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ func TestUpdate(t *testing.T) {
159159

160160
mbtest.AssertEndpointCalled(t, http.MethodPatch, "/groups/group-id")
161161
mbtest.AssertTestdata(t, "groupRequestUpdateObject.json", mbtest.Request.Body)
162+
163+
if mbtest.Request.ContentType != "application/json" {
164+
t.Fatalf("got %s, expected application/json", mbtest.Request.ContentType)
165+
}
162166
}
163167

164168
func TestAddContacts(t *testing.T) {
@@ -169,10 +173,11 @@ func TestAddContacts(t *testing.T) {
169173
t.Fatalf("unexpected error removing Contacts from Group: %s", err)
170174
}
171175

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

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)
179+
if mbtest.Request.ContentType != "application/x-www-form-urlencoded" {
180+
t.Fatalf("got %s, expected application/x-www-form-urlencoded", mbtest.Request.ContentType)
176181
}
177182
}
178183

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ids[]=first-contact-id&ids[]=second-contact-id

internal/mbtest/test_server.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import (
1010
)
1111

1212
type request struct {
13-
Body []byte
14-
Method string
15-
URL *url.URL
13+
Body []byte
14+
ContentType, Method string
15+
URL *url.URL
1616
}
1717

1818
// Request contains the lastly received http.Request by the fake server.
@@ -35,8 +35,9 @@ func EnableServer(m *testing.M) {
3535
func initAndStartServer() {
3636
server = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3737
Request = request{
38-
Method: r.Method,
39-
URL: r.URL,
38+
ContentType: r.Header.Get("Content-Type"),
39+
Method: r.Method,
40+
URL: r.URL,
4041
}
4142

4243
var err error

0 commit comments

Comments
 (0)