Skip to content

Commit 1e9cd61

Browse files
committed
Merge branch 'add-contacts' into v5_staging
2 parents 81a481c + 1e87762 commit 1e9cd61

23 files changed

+691
-114
lines changed

balance/balance_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"testing"
66

77
messagebird "github.com/messagebird/go-rest-api"
8-
"github.com/messagebird/go-rest-api/internal/messagebirdtest"
8+
"github.com/messagebird/go-rest-api/internal/mbtest"
99
)
1010

1111
const Epsilon float32 = 0.001
@@ -15,12 +15,12 @@ func cmpFloat32(a, b float32) bool {
1515
}
1616

1717
func TestMain(m *testing.M) {
18-
messagebirdtest.EnableServer(m)
18+
mbtest.EnableServer(m)
1919
}
2020

2121
func TestRead(t *testing.T) {
22-
messagebirdtest.WillReturnTestdata(t, "balance.json", http.StatusOK)
23-
client := messagebirdtest.Client(t)
22+
mbtest.WillReturnTestdata(t, "balance.json", http.StatusOK)
23+
client := mbtest.Client(t)
2424

2525
balance, err := Read(client)
2626
if err != nil {
@@ -41,8 +41,8 @@ func TestRead(t *testing.T) {
4141
}
4242

4343
func TestReadError(t *testing.T) {
44-
messagebirdtest.WillReturnAccessKeyError()
45-
client := messagebirdtest.Client(t)
44+
mbtest.WillReturnAccessKeyError()
45+
client := mbtest.Client(t)
4646

4747
_, err := Read(client)
4848

client.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,25 +109,30 @@ func (c *Client) Request(v interface{}, method, path string, data interface{}) e
109109
c.DebugLog.Printf("HTTP RESPONSE: %s", string(responseBody))
110110
}
111111

112-
// Status code 500 is a server error and means nothing can be done at this
113-
// point.
114-
if response.StatusCode == 500 {
115-
return ErrUnexpectedResponse
116-
}
117-
// Status codes 200 and 201 are indicative of being able to convert the
118-
// response body to the struct that was specified.
119-
if response.StatusCode == 200 || response.StatusCode == 201 {
112+
switch response.StatusCode {
113+
case http.StatusOK, http.StatusCreated:
114+
// Status codes 200 and 201 are indicative of being able to convert the
115+
// response body to the struct that was specified.
120116
if err := json.Unmarshal(responseBody, &v); err != nil {
121117
return fmt.Errorf("could not decode response JSON, %s: %v", string(responseBody), err)
122118
}
119+
123120
return nil
124-
}
121+
case http.StatusNoContent:
122+
// Status code 204 is returned for successful DELETE requests. Don't try to
123+
// unmarshal the body: that would return errors.
124+
return nil
125+
case http.StatusInternalServerError:
126+
// Status code 500 is a server error and means nothing can be done at this
127+
// point.
128+
return ErrUnexpectedResponse
129+
default:
130+
// Anything else than a 200/201/204/500 should be a JSON error.
131+
var errorResponse ErrorResponse
132+
if err := json.Unmarshal(responseBody, &errorResponse); err != nil {
133+
return err
134+
}
125135

126-
// Anything else than a 200/201/500 should be a JSON error.
127-
var errorResponse ErrorResponse
128-
if err := json.Unmarshal(responseBody, &errorResponse); err != nil {
129-
return err
136+
return errorResponse
130137
}
131-
132-
return errorResponse
133138
}

contact/contact.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package contact
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
"net/url"
8+
"strconv"
9+
"time"
10+
11+
messagebird "github.com/messagebird/go-rest-api"
12+
)
13+
14+
// Contact gets returned by the API.
15+
type Contact struct {
16+
ID string
17+
HRef string
18+
MSISDN int64
19+
FirstName string
20+
LastName string
21+
CustomDetails struct {
22+
Custom1 string
23+
Custom2 string
24+
Custom3 string
25+
Custom4 string
26+
}
27+
Groups struct {
28+
TotalCount int
29+
HRef string
30+
}
31+
Messages struct {
32+
TotalCount int
33+
HRef string
34+
}
35+
CreatedDatetime time.Time
36+
UpdatedDatetime time.Time
37+
}
38+
39+
type ContactList struct {
40+
Limit, Offset int
41+
Count, TotalCount int
42+
Items []Contact
43+
}
44+
45+
// ListOptions can be used to set pagination options in List().
46+
type ListOptions struct {
47+
Limit, Offset int
48+
}
49+
50+
// Request represents a contact for write operations, e.g. for creating a new
51+
// contact or updating an existing one.
52+
type Request struct {
53+
MSISDN string `json:"msisdn,omitempty"`
54+
FirstName string `json:"firstName,omitempty"`
55+
LastName string `json:"lastName,omitempty"`
56+
Custom1 string `json:"custom1,omitempty"`
57+
Custom2 string `json:"custom2,omitempty"`
58+
Custom3 string `json:"custom3,omitempty"`
59+
Custom4 string `json:"custom4,omitempty"`
60+
}
61+
62+
// path represents the path to the Contacts resource.
63+
const path = "contacts"
64+
65+
// DefaultListOptions provides reasonable values for List().
66+
var DefaultListOptions = &ListOptions{
67+
Limit: 20,
68+
Offset: 0,
69+
}
70+
71+
func Create(c *messagebird.Client, contactRequest *Request) (*Contact, error) {
72+
if err := validateCreate(contactRequest); err != nil {
73+
return nil, err
74+
}
75+
76+
contact := &Contact{}
77+
if err := c.Request(contact, http.MethodPost, path, contactRequest); err != nil {
78+
return nil, err
79+
}
80+
81+
return contact, nil
82+
}
83+
84+
func validateCreate(contactRequest *Request) error {
85+
if contactRequest.MSISDN == "" {
86+
return errors.New("msisdn is required")
87+
}
88+
89+
return nil
90+
}
91+
92+
// Delete attempts deleting the contact with the provided ID. If nil is returned,
93+
// the resource was deleted successfully.
94+
func Delete(c *messagebird.Client, id string) error {
95+
if id == "" {
96+
return errors.New("id is required")
97+
}
98+
99+
return c.Request(nil, http.MethodDelete, path+"/"+id, nil)
100+
}
101+
102+
// List retrieves a paginated list of contacts, based on the options provided.
103+
// It's worth noting DefaultListOptions.
104+
func List(c *messagebird.Client, options *ListOptions) (*ContactList, error) {
105+
query, err := listQuery(options)
106+
if err != nil {
107+
return nil, err
108+
}
109+
110+
contactList := &ContactList{}
111+
if err = c.Request(contactList, http.MethodGet, path+"?"+query, nil); err != nil {
112+
return nil, err
113+
}
114+
115+
return contactList, nil
116+
}
117+
118+
func listQuery(options *ListOptions) (string, error) {
119+
if options.Limit < 10 {
120+
return "", fmt.Errorf("minimum limit is 10, got %d", options.Limit)
121+
}
122+
123+
if options.Offset < 0 {
124+
return "", fmt.Errorf("offset can not be negative")
125+
}
126+
127+
values := &url.Values{}
128+
129+
values.Set("limit", strconv.Itoa(options.Limit))
130+
values.Set("offset", strconv.Itoa(options.Offset))
131+
132+
return values.Encode(), nil
133+
}
134+
135+
// Read retrieves the information of an existing contact.
136+
func Read(c *messagebird.Client, id string) (*Contact, error) {
137+
contact := &Contact{}
138+
if err := c.Request(contact, http.MethodGet, path+"/"+id, nil); err != nil {
139+
return nil, err
140+
}
141+
142+
return contact, nil
143+
}
144+
145+
// Update updates the record referenced by id with any values set in contactRequest.
146+
// Do not set any values that should not be updated.
147+
func Update(c *messagebird.Client, id string, contactRequest *Request) (*Contact, error) {
148+
contact := &Contact{}
149+
if err := c.Request(contact, http.MethodPatch, path+"/"+id, contactRequest); err != nil {
150+
return nil, err
151+
}
152+
153+
return contact, nil
154+
}

0 commit comments

Comments
 (0)