Skip to content

Commit

Permalink
Merge pull request #30 from mailerlite/feature/no-ref/go-interface-mocks
Browse files Browse the repository at this point in the history
chore: add interfaces and export types
  • Loading branch information
robgordon89 authored Nov 21, 2024
2 parents 3f1dc72 + e1a9da3 commit 45a1c70
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 145 deletions.
38 changes: 35 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ MailerLite Golang SDK
- [Campaign languages](#languages)
- [Get a list of languages](#get-a-list-of-languages)

# Installation
We recommend using this package with golang [modules](https://github.com/golang/go/wiki/Modules)

```
$ go get github.com/mailerlite/mailerlite-go
```

# Usage

## Subscribers

### Get a list of subscribers
Expand Down Expand Up @@ -132,7 +141,7 @@ func main() {
log.Fatal(err)
}

log.Print(subscribers.Data.Email)
log.Print(subscriber.Data.Email)
}
```

Expand Down Expand Up @@ -253,7 +262,7 @@ func main() {

ctx := context.TODO()

_, _, err := client.Subscriber.Delete(ctx, "subscriber-id")
_, err := client.Subscriber.Delete(ctx, "subscriber-id")
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -457,7 +466,7 @@ func main() {

ctx := context.TODO()

_, _, err := client.Group.UnAssign(ctx, "group-id", "subscriber-id")
_, err := client.Group.UnAssign(ctx, "group-id", "subscriber-id")
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -1424,6 +1433,29 @@ func main() {

# Testing

We provide interfaces for all services to help with testing

```go
type mockSubscriberService struct {
mailerlite.SubscriberService
}

func (m *mockSubscriberService) List(ctx context.Context, options *mailerlite.ListSubscriberOptions) (*mailerlite.RootSubscribers, *mailerlite.Response, error) {
return &mailerlite.RootSubscribers{Data: []mailerlite.Subscriber{{Email: "[email protected]"}}}, nil, nil
}

func TestListSubscribers(t *testing.T) {
client := &mailerlite.Client{}
client.Subscriber = &mockSubscriberService{}

ctx := context.Background()
result, _, err := client.Subscriber.List(ctx, nil)
if err != nil || len(result.Data) == 0 || result.Data[0].Email != "[email protected]" {
t.Fatalf("mock failed")
}
}
```

[pkg/testing](https://golang.org/pkg/testing/)

```
Expand Down
29 changes: 19 additions & 10 deletions automations.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,28 @@ import (

const automationEndpoint = "/automations"

type AutomationService service
// AutomationService defines an interface for automation-related operations.
type AutomationService interface {
List(ctx context.Context, options *ListAutomationOptions) (*RootAutomations, *Response, error)
Get(ctx context.Context, automationID string) (*RootAutomation, *Response, error)
Subscribers(ctx context.Context, options *ListAutomationSubscriberOptions) (*RootAutomationsSubscriber, *Response, error)
}

type automationService struct {
*service
}

type rootAutomation struct {
type RootAutomation struct {
Data Automation `json:"data"`
}

type rootAutomations struct {
type RootAutomations struct {
Data []Automation `json:"data"`
Links Links `json:"links"`
Meta Meta `json:"meta"`
}

type rootAutomationsSubscriber struct {
type RootAutomationsSubscriber struct {
Data []AutomationSubscriber `json:"data"`
Links Links `json:"links"`
Meta Meta `json:"meta"`
Expand Down Expand Up @@ -168,13 +177,13 @@ type ListAutomationSubscriberOptions struct {
Limit int `url:"limit,omitempty"`
}

func (s *AutomationService) List(ctx context.Context, options *ListAutomationOptions) (*rootAutomations, *Response, error) {
func (s *automationService) List(ctx context.Context, options *ListAutomationOptions) (*RootAutomations, *Response, error) {
req, err := s.client.newRequest(http.MethodGet, automationEndpoint, options)
if err != nil {
return nil, nil, err
}

root := new(rootAutomations)
root := new(RootAutomations)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -183,14 +192,14 @@ func (s *AutomationService) List(ctx context.Context, options *ListAutomationOpt
return root, res, nil
}

func (s *AutomationService) Get(ctx context.Context, automationID string) (*rootAutomation, *Response, error) {
func (s *automationService) Get(ctx context.Context, automationID string) (*RootAutomation, *Response, error) {
path := fmt.Sprintf("%s/%s", automationEndpoint, automationID)
req, err := s.client.newRequest(http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(rootAutomation)
root := new(RootAutomation)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -199,15 +208,15 @@ func (s *AutomationService) Get(ctx context.Context, automationID string) (*root
return root, res, nil
}

func (s *AutomationService) Subscribers(ctx context.Context, options *ListAutomationSubscriberOptions) (*rootAutomationsSubscriber, *Response, error) {
func (s *automationService) Subscribers(ctx context.Context, options *ListAutomationSubscriberOptions) (*RootAutomationsSubscriber, *Response, error) {
path := fmt.Sprintf("%s/%s/activity", automationEndpoint, options.AutomationID)

req, err := s.client.newRequest(http.MethodGet, path, options)
if err != nil {
return nil, nil, err
}

root := new(rootAutomationsSubscriber)
root := new(RootAutomationsSubscriber)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand Down
72 changes: 44 additions & 28 deletions campaigns.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,43 @@ import (

const campaignEndpoint = "/campaigns"

type CampaignService service
// CampaignService defines an interface for campaign-related operations.
type CampaignService interface {
List(ctx context.Context, options *ListCampaignOptions) (*RootCampaigns, *Response, error)
Get(ctx context.Context, campaignID string) (*RootCampaign, *Response, error)
Create(ctx context.Context, campaign *CreateCampaign) (*RootCampaign, *Response, error)
Update(ctx context.Context, campaignID string, campaign *UpdateCampaign) (*RootCampaign, *Response, error)
Schedule(ctx context.Context, campaignID string, campaign *ScheduleCampaign) (*RootCampaign, *Response, error)
Cancel(ctx context.Context, campaignID string) (*RootCampaign, *Response, error)
Subscribers(ctx context.Context, options *ListCampaignSubscriberOptions) (*RootCampaignSubscribers, *Response, error)
Languages(ctx context.Context) (*RootCampaignLanguages, *Response, error)
Delete(ctx context.Context, campaignID string) (*Response, error)
}

// campaignService implements CampaignService.
type campaignService struct {
*service
}

// rootCampaigns - campaigns response
type rootCampaigns struct {
// RootCampaigns - campaigns response
type RootCampaigns struct {
Data []Campaign `json:"data"`
Links Links `json:"links"`
Meta Meta `json:"meta"`
}

// rootCampaign - single campaign response
type rootCampaign struct {
// RootCampaign - single campaign response
type RootCampaign struct {
Data Campaign `json:"data"`
}

type rootCampaignSubscribers struct {
type RootCampaignSubscribers struct {
Data []CampaignSubscriber `json:"data"`
Links Links `json:"links"`
Meta Meta `json:"meta"`
}

type rootCampaignLanguages struct {
type RootCampaignLanguages struct {
Data []CampaignLanguage
}

Expand Down Expand Up @@ -123,21 +139,21 @@ type Stats struct {
ClickToOpenRate ClickToOpenRate `json:"click_to_open_rate"`
}

// ListCampaignOptions - modifies the behavior of CampaignService.List method
// ListCampaignOptions - modifies the behavior of campaignService.List method
type ListCampaignOptions struct {
Filters *[]Filter `json:"filters,omitempty"`
Page int `url:"page,omitempty"`
Limit int `url:"limit,omitempty"`
}

// GetCampaignOptions - modifies the behavior of CampaignService.Get method
// GetCampaignOptions - modifies the behavior of campaignService.Get method
type GetCampaignOptions struct {
ID int `json:"id,omitempty"`
}

type UpdateCampaign CreateCampaign

// CreateCampaign - modifies the behavior of CampaignService.Create method
// CreateCampaign - modifies the behavior of campaignService.Create method
type CreateCampaign struct {
Name string `json:"name"`
LanguageID int `json:"language_id,omitempty"`
Expand Down Expand Up @@ -177,7 +193,7 @@ type ResendSettings struct {
BValue BValue `json:"b_value"`
}

// ScheduleCampaign - modifies the behavior of CampaignService.Schedule method
// ScheduleCampaign - modifies the behavior of campaignService.Schedule method
type ScheduleCampaign struct {
Delivery string `json:"delivery"`
Schedule *Schedule `json:"schedule,omitempty"`
Expand Down Expand Up @@ -223,13 +239,13 @@ type ListCampaignSubscriberOptions struct {
}

// List - list of campaigns
func (s *CampaignService) List(ctx context.Context, options *ListCampaignOptions) (*rootCampaigns, *Response, error) {
func (s *campaignService) List(ctx context.Context, options *ListCampaignOptions) (*RootCampaigns, *Response, error) {
req, err := s.client.newRequest(http.MethodGet, campaignEndpoint, options)
if err != nil {
return nil, nil, err
}

root := new(rootCampaigns)
root := new(RootCampaigns)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -239,14 +255,14 @@ func (s *CampaignService) List(ctx context.Context, options *ListCampaignOptions
}

// Get - get a single campaign ID
func (s *CampaignService) Get(ctx context.Context, campaignID string) (*rootCampaign, *Response, error) {
func (s *campaignService) Get(ctx context.Context, campaignID string) (*RootCampaign, *Response, error) {
path := fmt.Sprintf("%s/%s", campaignEndpoint, campaignID)
req, err := s.client.newRequest(http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(rootCampaign)
root := new(RootCampaign)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -255,13 +271,13 @@ func (s *CampaignService) Get(ctx context.Context, campaignID string) (*rootCamp
return root, res, nil
}

func (s *CampaignService) Create(ctx context.Context, campaign *CreateCampaign) (*rootCampaign, *Response, error) {
func (s *campaignService) Create(ctx context.Context, campaign *CreateCampaign) (*RootCampaign, *Response, error) {
req, err := s.client.newRequest(http.MethodPost, campaignEndpoint, campaign)
if err != nil {
return nil, nil, err
}

root := new(rootCampaign)
root := new(RootCampaign)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -270,14 +286,14 @@ func (s *CampaignService) Create(ctx context.Context, campaign *CreateCampaign)
return root, res, nil
}

func (s *CampaignService) Update(ctx context.Context, campaignID string, campaign *UpdateCampaign) (*rootCampaign, *Response, error) {
func (s *campaignService) Update(ctx context.Context, campaignID string, campaign *UpdateCampaign) (*RootCampaign, *Response, error) {
path := fmt.Sprintf("%s/%s", campaignEndpoint, campaignID)
req, err := s.client.newRequest(http.MethodPut, path, campaign)
if err != nil {
return nil, nil, err
}

root := new(rootCampaign)
root := new(RootCampaign)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -286,14 +302,14 @@ func (s *CampaignService) Update(ctx context.Context, campaignID string, campaig
return root, res, nil
}

func (s *CampaignService) Schedule(ctx context.Context, campaignID string, campaign *ScheduleCampaign) (*rootCampaign, *Response, error) {
func (s *campaignService) Schedule(ctx context.Context, campaignID string, campaign *ScheduleCampaign) (*RootCampaign, *Response, error) {
path := fmt.Sprintf("%s/%s/schedule", campaignEndpoint, campaignID)
req, err := s.client.newRequest(http.MethodPost, path, campaign)
if err != nil {
return nil, nil, err
}

root := new(rootCampaign)
root := new(RootCampaign)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -303,14 +319,14 @@ func (s *CampaignService) Schedule(ctx context.Context, campaignID string, campa
}

// Cancel - cancel a single campaign
func (s *CampaignService) Cancel(ctx context.Context, campaignID string) (*rootCampaign, *Response, error) {
func (s *campaignService) Cancel(ctx context.Context, campaignID string) (*RootCampaign, *Response, error) {
path := fmt.Sprintf("%s/%s/cancel", campaignEndpoint, campaignID)
req, err := s.client.newRequest(http.MethodPost, path, nil)
if err != nil {
return nil, nil, err
}

root := new(rootCampaign)
root := new(RootCampaign)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -320,15 +336,15 @@ func (s *CampaignService) Cancel(ctx context.Context, campaignID string) (*rootC
}

// Subscribers - get subscribers activity of a campaign
func (s *CampaignService) Subscribers(ctx context.Context, options *ListCampaignSubscriberOptions) (*rootCampaignSubscribers, *Response, error) {
func (s *campaignService) Subscribers(ctx context.Context, options *ListCampaignSubscriberOptions) (*RootCampaignSubscribers, *Response, error) {
path := fmt.Sprintf("%s/%s/reports/subscriber-activity", campaignEndpoint, options.CampaignID)

req, err := s.client.newRequest(http.MethodPost, path, options)
if err != nil {
return nil, nil, err
}

root := new(rootCampaignSubscribers)
root := new(RootCampaignSubscribers)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -337,14 +353,14 @@ func (s *CampaignService) Subscribers(ctx context.Context, options *ListCampaign
return root, res, nil
}

func (s *CampaignService) Languages(ctx context.Context) (*rootCampaignLanguages, *Response, error) {
func (s *campaignService) Languages(ctx context.Context) (*RootCampaignLanguages, *Response, error) {
path := fmt.Sprintf("%s/languages", campaignEndpoint)
req, err := s.client.newRequest(http.MethodGet, path, nil)
if err != nil {
return nil, nil, err
}

root := new(rootCampaignLanguages)
root := new(RootCampaignLanguages)
res, err := s.client.do(ctx, req, root)
if err != nil {
return nil, res, err
Expand All @@ -353,7 +369,7 @@ func (s *CampaignService) Languages(ctx context.Context) (*rootCampaignLanguages
return root, res, nil
}

func (s *CampaignService) Delete(ctx context.Context, campaignID string) (*Response, error) {
func (s *campaignService) Delete(ctx context.Context, campaignID string) (*Response, error) {
path := fmt.Sprintf("%s/%s", campaignEndpoint, campaignID)

req, err := s.client.newRequest(http.MethodDelete, path, nil)
Expand Down
Loading

0 comments on commit 45a1c70

Please sign in to comment.