Skip to content

Commit

Permalink
feat: implement go novu endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
samsoft00 committed Jun 27, 2022
1 parent 9dc8f4b commit a6b2ce7
Show file tree
Hide file tree
Showing 17 changed files with 818 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
.idea

# Test binary, built with `go test -c`
*.test
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
OUTPUT = main

.PHONY: test
test:
go test ./...

.PHONY: clean
clean:
rm -f $(OUTPUT)
85 changes: 84 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,84 @@
# go
# Novu's API v1 Go Library

Novu's API exposes the entire Novu features via a standardized programmatic interface. Please refer to the full [documentation](https://docs.novu.co/docs/overview/introduction) to learn more.

## Installation & Usage
Install the package to your GoLang project.
```golang
go get github.com/novuhq/go-novu
```

## Getting Started

Please follow the [installation procedure](#installation--usage) and then run the following:

```golang
package main

import (
"context"
"fmt"
novu "github.com/novuhq/go-novu/lib"
"log"
)

func main() {
apiKey := "ee35a7412bc654b3ac3b5cf649daa319"
eventId := "gs-cooperative"

ctx := context.Background()
to := map[string]interface{}{
"lastName": "Doe",
"firstName": "John",
"subscriberId": "[email protected]",
"email": "[email protected]",
}

payload := map[string]interface{}{
"name": "Hello World",
"organization": map[string]interface{}{
"logo": "https://happycorp.com/logo.png",
},
}

data := novu.ITriggerPayloadOptions{To: to, Payload: payload}
novuClient := novu.NewAPIClient(apiKey, &novu.Config{})

resp, err := novuClient.EventApi.Trigger(ctx, eventId, data)
if err != nil {
log.Fatal("novu error", err.Error())
return
}

fmt.Println(resp)
}
```

## Documentation for API Endpoints

Class | Method | HTTP request | Description
------------ |------------------------------------------------|---------------------------------------| -------------
*EventApi* | [**Trigger**](docs/SubscriberApi.md#identify) | **Post** /events/trigger | Get your account information, plan and credits details
*SubscriberApi* | [**Identify**](docs/SubscriberApi.md#identify) | **Post** /subscribers | Get your account information, plan and credits details
*SubscriberApi* | [**Update**](docs/SubscriberApi.md#update) | **Put** /subscribers/:subscriberID | Get your account information, plan and credits details
*SubscriberApi* | [**Delete**](docs/SubscriberApi.md#delete) | **Delete** /subscribers/:subscriberID | Get your account information, plan and credits details

## Authorization (api-key)

- **Type**: API key
- **API key parameter name**: ApiKey
- **Location**: HTTP header

## Support and Feedback

Be sure to visit the Novu official [documentation website](https://docs.novu.co/docs) for additional information about our API.

If you find a bug, please post the issue on [Github](https://github.com/novuhq/go-novu/issues).

As always, if you need additional assistance, join our Discord us a note [here](https://discord.gg/TT6TttXjRe).

## Contributors

Name |
------------ |
[Oyewole Samuel](https://github.com/samsoft00) |
85 changes: 85 additions & 0 deletions cmd/default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package main

import (
"context"
"fmt"
novu "github.com/novuhq/go-novu/lib"
"log"
)

func main() {
subscriberID := "3ac3b5cf649daa319ee35a7412bc654b"
apiKey := "ee35a7412bc654b3ac3b5cf649daa319"
eventId := "gs-cooperative"

ctx := context.Background()
to := map[string]interface{}{
"lastName": "Doe",
"firstName": "John",
"subscriberId": "[email protected]",
"email": "[email protected]",
}

payload := map[string]interface{}{
"name": "Hello World",
"organization": map[string]interface{}{
"logo": "https://happycorp.com/logo.png",
},
}

novuClient := novu.NewAPIClient(apiKey, &novu.Config{})

// Trigger
triggerResp, err := novuClient.EventApi.Trigger(ctx, eventId, novu.ITriggerPayloadOptions{
To: to,
Payload: payload,
})
if err != nil {
log.Fatal("Novu error", err.Error())
return
}

fmt.Println(triggerResp)

// Subscriber
subscriber := novu.SubscriberPayload{
LastName: "Skjæveland",
Email: "[email protected]",
Avatar: "https://randomuser.me/api/portraits/thumb/women/79.jpg",
Data: map[string]interface{}{
"location": map[string]interface{}{
"city": "Ballangen",
"state": "Aust-Agder",
"country": "Norway",
"postcode": "7481",
},
},
}

resp, err := novuClient.SubscriberApi.Identify(ctx, subscriberID, subscriber)
if err != nil {
log.Fatal("Subscriber error: ", err.Error())
return
}

fmt.Println(resp)

// update subscriber
updateSubscriber := novu.SubscriberPayload{FirstName: "Susan"}

updateResp, err := novuClient.SubscriberApi.Update(ctx, subscriberID, updateSubscriber)
if err != nil {
log.Fatal("Update subscriber error: ", err.Error())
return
}

fmt.Println(updateResp)

// delete subscriber
deleteResp, err := novuClient.SubscriberApi.Delete(ctx, subscriberID)
if err != nil {
log.Fatal("Update subscriber error: ", err.Error())
return
}
fmt.Println(deleteResp)
}
14 changes: 14 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module github.com/novuhq/go-novu

go 1.18

require (
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.5
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
17 changes: 17 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
42 changes: 42 additions & 0 deletions lib/event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lib

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
)

type IEvent interface {
Trigger(ctx context.Context, eventId string, data ITriggerPayloadOptions) (EventResponse, error)
}

type EventService service

func (e *EventService) Trigger(ctx context.Context, eventId string, data ITriggerPayloadOptions) (EventResponse, error) {
var resp EventResponse
URL := fmt.Sprintf(e.client.config.BackendURL+"/%s", "events/trigger")

reqBody := EventRequest{
Name: eventId,
To: data.To,
Payload: data.Payload,
}

jsonBody, _ := json.Marshal(reqBody)

req, err := http.NewRequestWithContext(ctx, http.MethodPost, URL, bytes.NewBuffer(jsonBody))
if err != nil {
return resp, err
}

err = e.client.sendRequest(req, &resp)
if err != nil {
return resp, err
}

return resp, nil
}

var _ IEvent = &EventService{}
80 changes: 80 additions & 0 deletions lib/event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package lib_test

import (
"bytes"
"context"
"encoding/json"
"github.com/novuhq/go-novu/lib"
"github.com/stretchr/testify/require"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

const (
novuApiKey = "test-API-key"
novuEventId = "test-novu"
)

func fileToStruct(filepath string, s interface{}) io.Reader {
bb, _ := ioutil.ReadFile(filepath)
json.Unmarshal(bb, s)
return bytes.NewReader(bb)
}

func TestEventServiceTrigger_Success(t *testing.T) {
var (
receivedBody lib.ITriggerPayloadOptions
expectedTokenRequest lib.ITriggerPayloadOptions
triggerPayload lib.ITriggerPayloadOptions
)

eventService := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if err := json.NewDecoder(req.Body).Decode(&receivedBody); err != nil {
log.Printf("error in unmarshalling %+v", err)
w.WriteHeader(http.StatusBadRequest)
return
}

t.Run("Header must contain ApiKey", func(t *testing.T) {
authKey := req.Header.Get("Authorization")
assert.True(t, strings.Contains(authKey, novuApiKey))
assert.True(t, strings.HasPrefix(authKey, "ApiKey"))
})

t.Run("URL and request method is as expected", func(t *testing.T) {
expectedURL := "/v1/events/trigger"
assert.Equal(t, http.MethodPost, req.Method)
assert.Equal(t, expectedURL, req.RequestURI)
})

t.Run("Request is as expected", func(t *testing.T) {
fileToStruct(filepath.Join("../testdata", "novu_send_trigger.json"), &expectedTokenRequest)
assert.Equal(t, expectedTokenRequest, receivedBody)
})

var resp lib.EventResponse
fileToStruct(filepath.Join("../testdata", "novu_send_trigger_response.json"), &resp)

w.WriteHeader(http.StatusOK)
bb, _ := json.Marshal(resp)
w.Write(bb)
}))

defer eventService.Close()

ctx := context.Background()
fileToStruct(filepath.Join("../testdata", "novu_send_trigger.json"), &triggerPayload)

c := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: eventService.URL})
_, err := c.EventApi.Trigger(ctx, novuEventId, triggerPayload)

require.Nil(t, err)
}
Loading

0 comments on commit a6b2ce7

Please sign in to comment.