resthooks

package module
v0.0.0-...-bf95aa8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 23, 2022 License: MIT Imports: 10 Imported by: 5

README

go-resthooks

REST Hooks library for Golang.

Features
  • Subscribe/Unsubscribe endpoints
  • Exponential retries
  • Decoupled subscription storage
Todo
  • Implement, list, get and update subscription endpoints
Installation
$ dep ensure -add github.com/marconi/go-resthooks
Usage
import (
    "net/http"

    resthooks "github.com/marconi/go-resthooks"
)

func main() {
    ...
    rh := resthooks.NewResthook(store)
    defer rh.Close()

    http.Handle("/hooks/", rh.Handler())
}

Where store is a struct that implements the ResthookStore interface.

Its up to you where or how you would store the subscription, as long as you implement the interface and pass the data access object. This gives you flexibility to choose your favorite database and ORM.

Also rh.Handler() returns an http.Handler so you can mount it on prefix and any route that supports that standard interface. You can even wrap it with say authentication middleware, all 3rd-party middlewares that support the standard intefface http.Handle should work. Here we are just using the built-in http.Handle. In this setup, we'll get the following routes:

  1. POST /hooks/subscribe
  2. DELETE /hooks/unsubscribe

The first one is used to create a subscription and the second one to delete the subscription. Again how you handle this is up to your ResthookStore implementation, for example you can choose soft-delete when deleting subscription for auditing later.

Once you have a subscription, you can notify the subscribers with:

userId := 1
event := "post_created"
data := new(SampleData)

if err := rh.Notify(userId, event, data); err != nil {
  // handle error
}

If you want to get notified with what happened to the notifications, you subscribe to the results channel with:

go func() {
  for data := range rh.GetResults() {
    // handle data
  }
}()

Here data is an instance of Notification so you can use the Status field if it was successful or not. Note that by default if a notification fails, it'll retry it 3 more times and only then will it give-up. The retry works as follows:

// start retrying after 5 seconds and
// grow exponentially after that:
// 1st retry = after 5 seconds.
// 2nd retry = 5 * 3 = after 15 seconds.
// 3rd retry (final) = 5 * 3 * 3 = after 45 seconds.

See https://godoc.org/github.com/marconi/go-resthooks#pkg-constants

Which you can configure with Config.

Documentation

Index

Constants

View Source
const (
	// start retrying after 5 seconds and
	// grow exponentially after that:
	// 1st retry = after 5 seconds
	// 2nd retry = 5*3 = after 15 seconds
	// 3rd retry (final) = 5*3*3 = after 45 seconds
	DefaultInitialRetry    int = 5
	DefaultRetryMultiplier int = 3

	// maximum number of attempts
	DefaultMaxRetry int = 3
)

Variables

This section is empty.

Functions

func NewHandler

func NewHandler(rh *Resthook) http.Handler

Types

type Config

type Config struct {
	InitialRetry    int
	RetryMultiplier int
	MaxRetry        int
}

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*Handler) Subscribe

func (h *Handler) Subscribe(w http.ResponseWriter, r *http.Request)

func (*Handler) Unsubscribe

func (h *Handler) Unsubscribe(w http.ResponseWriter, r *http.Request)

type Notification

type Notification struct {
	Subscription *Subscription
	Data         []byte
	Status       Status
	Retries      int
}

type Resthook

type Resthook struct {
	// contains filtered or unexported fields
}

func NewResthook

func NewResthook(store ResthookStore, config ...Config) Resthook

func (Resthook) Close

func (rh Resthook) Close()

func (Resthook) DeleteById

func (rh Resthook) DeleteById(id int, r *http.Request) error

func (Resthook) FindById

func (rh Resthook) FindById(id int) (*Subscription, error)

func (Resthook) GetResults

func (rh Resthook) GetResults() <-chan *Notification

func (Resthook) Handler

func (rh Resthook) Handler() http.Handler

func (Resthook) Notify

func (rh Resthook) Notify(userId int, event string, data interface{}) error

func (Resthook) Save

func (rh Resthook) Save(s *Subscription, r *http.Request) error

type ResthookStore

type ResthookStore interface {
	// Creates subscription if it doesn't have id
	// and populates the id, otherwise updates it.
	Save(*Subscription, *http.Request) error

	FindById(int) (*Subscription, error)
	FindByUserId(int, string) (*Subscription, error)
	DeleteById(int, *http.Request) error
}

ResthookStore defines APIs for subscription's CRUD operations. Using this you can customise where and how data is actually being stored. Or that you actually use soft-delete to preserve history of subscription.

type Status

type Status int
const (
	STATUS_PENDING Status = iota
	STATUS_SUCCESS
	STATUS_FAILED
)

type Subscription

type Subscription struct {
	Id        int    `json:"id"`
	UserId    int    `json:"user_id"`
	Event     string `json:"event"`
	TargetUrl string `json:"target_url"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL