Add functions of create, get, update, delete and list webhooks (#146)

* Add webhook creation function

* Add webhook list function

* Add webhook delete function

* Add webhook get function

* Add webhook update function

* Update documentation related to webhooks

* Fix addressed issues on code review
This commit is contained in:
Bülent Rahim Kazancı 2020-05-02 17:42:37 +03:00 committed by GitHub
parent 497963d8a5
commit 21b349dbdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 230 additions and 0 deletions

View File

@ -42,6 +42,11 @@ Currently supports **v2** only, if you want to use **v1**, use **v1.1.4** git ta
* PATCH /v2/payments/billing-plans/***ID***
* POST /v2/payments/billing-agreements
* POST /v2/payments/billing-agreements/***TOKEN***/agreement-execute
* POST /v1/notifications/webhooks
* GET /v1/notifications/webhooks
* GET /v1/notifications/webhooks/**ID**
* PATCH /v1/notifications/webhooks/**ID**
* DELETE /v1/notifications/webhooks/**ID**
* POST /v1/notifications/verify-webhook-signature
### Missing endpoints
@ -281,6 +286,42 @@ c.GetCreditCard("CARD-ID-123")
c.GetCreditCards(nil)
```
### Webhooks
```go
// Create a webhook
c.CreateWebhook(paypal.CreateWebhookRequest{
URL: "webhook URL",
EventTypes: []paypal.WebhookEventType{
paypal.WebhookEventType{
Name: "PAYMENT.AUTHORIZATION.CREATED",
},
},
})
// Update a registered webhook
c.UpdateWebhook("WebhookID", []paypal.WebhookField{
paypal.WebhookField{
Operation: "replace",
Path: "/event_types",
Value: []interface{}{
map[string]interface{}{
"name": "PAYMENT.SALE.REFUNDED",
},
},
},
})
// Get a registered webhook
c.GetWebhook("WebhookID")
// Delete a webhook
c.DeleteWebhook("WebhookID")
// List registered webhooks
c.ListWebhooks(paypal.AncorTypeApplication)
```
### How to Contribute
* Fork a repository

0
go.sum Normal file
View File

View File

@ -132,3 +132,85 @@ func TestPatchCreditCard(t *testing.T) {
t.Errorf("Error is expected for empty update info")
}
}
// Creates, gets, and deletes single webhook
func TestCreateAndGetWebhook(t *testing.T) {
c, _ := NewClient(testClientID, testSecret, APIBaseSandBox)
c.GetAccessToken()
payload := &CreateWebhookRequest{
URL: "https://example.com/paypal_webhooks",
EventTypes: []WebhookEventType{
WebhookEventType{
Name: "PAYMENT.AUTHORIZATION.CREATED",
},
},
}
createdWebhook, err := c.CreateWebhook(payload)
if err != nil {
t.Errorf("Webhook couldn't be created, error %v", err)
}
_, err = c.GetWebhook(createdWebhook.ID)
if err != nil {
t.Errorf("An error occurred while getting webhook, error %v", err)
}
err = c.DeleteWebhook(createdWebhook.ID)
if err != nil {
t.Errorf("An error occurred while webhooks deletion, error %v", err)
}
}
// Creates, updates, and deletes single webhook
func TestCreateAndUpdateWebhook(t *testing.T) {
c, _ := NewClient(testClientID, testSecret, APIBaseSandBox)
c.GetAccessToken()
creationPayload := &CreateWebhookRequest{
URL: "https://example.com/paypal_webhooks",
EventTypes: []WebhookEventType{
WebhookEventType{
Name: "PAYMENT.AUTHORIZATION.CREATED",
},
},
}
createdWebhook, err := c.CreateWebhook(creationPayload)
if err != nil {
t.Errorf("Webhook couldn't be created, error %v", err)
}
updatePayload := []WebhookField{
WebhookField{
Operation: "replace",
Path: "/event_types",
Value: []interface{}{
map[string]interface{}{
"name": "PAYMENT.SALE.REFUNDED",
},
},
},
}
_, err = c.UpdateWebhook(createdWebhook.ID, updatePayload)
if err != nil {
t.Errorf("Couldn't update webhook, error %v", err)
}
err = c.DeleteWebhook(createdWebhook.ID)
if err != nil {
t.Errorf("An error occurred while webhooks deletion, error %v", err)
}
}
func TestListWebhooks(t *testing.T) {
c, _ := NewClient(testClientID, testSecret, APIBaseSandBox)
c.GetAccessToken()
_, err := c.ListWebhooks(AncorTypeApplication)
if err != nil {
t.Errorf("Cannot registered list webhooks, error %v", err)
}
}

View File

@ -124,6 +124,11 @@ const (
LinkRelActionURL string = "action_url"
)
const (
AncorTypeApplication string = "APPLICATION"
AncorTypeAccount string = "ACCOUNT"
)
type (
// JSONTime overrides MarshalJson method to format in ISO8601
JSONTime time.Time
@ -963,10 +968,20 @@ type (
UserAction string `json:"user_action,omitempty"`
}
// VerifyWebhookResponse struct
VerifyWebhookResponse struct {
VerificationStatus string `json:"verification_status,omitempty"`
}
// Webhook strunct
Webhook struct {
ID string `json:"id"`
URL string `json:"url"`
EventTypes []WebhookEventType `json:"event_types"`
Links []Link `json:"links"`
}
// WebhookEvent struct
WebhookEvent struct {
ID string `json:"id"`
CreateTime time.Time `json:"create_time"`
@ -979,6 +994,28 @@ type (
ResourceVersion string `json:"resource_version,omitempty"`
}
// WebhookEventType struct
WebhookEventType struct {
Name string `json:"name"`
Description string `json:"description"`
}
// CreateWebhookRequest struct
CreateWebhookRequest struct {
URL string `json:"url"`
EventTypes []WebhookEventType `json:"event_types"`
}
ListWebhookResponse struct {
Webhooks []Webhook `json:"webhooks"`
}
WebhookField struct {
Operation string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value"`
}
Resource struct {
// Payment Resource type
ID string `json:"id,omitempty"`

View File

@ -8,6 +8,76 @@ import (
"net/http"
)
// CreateWebhook - Subscribes your webhook listener to events.
// Endpoint: POST /v1/notifications/webhooks
func (c *Client) CreateWebhook(createWebhookRequest *CreateWebhookRequest) (*Webhook, error) {
req, err := c.NewRequest(http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest)
webhook := &Webhook{}
if err != nil {
return webhook, err
}
err = c.SendWithAuth(req, webhook)
return webhook, err
}
// GetWebhook - Shows details for a webhook, by ID.
// Endpoint: GET /v1/notifications/webhooks/ID
func (c *Client) GetWebhook(webhookID string) (*Webhook, error) {
req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil)
webhook := &Webhook{}
if err != nil {
return webhook, err
}
err = c.SendWithAuth(req, webhook)
return webhook, err
}
// UpdateWebhook - Updates a webhook to replace webhook fields with new values.
// Endpoint: PATCH /v1/notifications/webhooks/ID
func (c *Client) UpdateWebhook(webhookID string, fields []WebhookField) (*Webhook, error) {
req, err := c.NewRequest(http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields)
webhook := &Webhook{}
if err != nil {
return webhook, err
}
err = c.SendWithAuth(req, webhook)
return webhook, err
}
// ListWebhooks - Lists webhooks for an app.
// Endpoint: GET /v1/notifications/webhooks
func (c *Client) ListWebhooks(anchorType string) (*ListWebhookResponse, error) {
if len(anchorType) == 0 {
anchorType = AncorTypeApplication
}
req, err := c.NewRequest(http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil)
q := req.URL.Query()
q.Add("anchor_type", anchorType)
req.URL.RawQuery = q.Encode()
resp := &ListWebhookResponse{}
if err != nil {
return nil, err
}
err = c.SendWithAuth(req, resp)
return resp, err
}
// DeleteWebhook - Deletes a webhook, by ID.
// Endpoint: DELETE /v1/notifications/webhooks/ID
func (c *Client) DeleteWebhook(webhookID string) error {
req, err := c.NewRequest(http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil)
if err != nil {
return err
}
err = c.SendWithAuth(req, nil)
return err
}
// VerifyWebhookSignature - Use this to verify the signature of a webhook recieved from paypal.
// Endpoint: POST /v1/notifications/verify-webhook-signature
func (c *Client) VerifyWebhookSignature(httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) {