rest

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 27, 2018 License: CC0-1.0 Imports: 12 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound signals that the resource is absent.
	// See CRUDRepo's SetReadFunc, SetUpdateFunc and SetDeleteFunc for the details.
	ErrNotFound = errors.New("no such entry")

	// ErrOptimisticLock signals that the latest version does not match the request.
	// See CRUDRepo's SetUpdateFunc and SetDeleteFunc for the details.
	ErrOptimisticLock = errors.New("lost optimistic lock")
)

Functions

func ReceiveJSON

func ReceiveJSON(dst interface{}, r *http.Request, w http.ResponseWriter) bool

ReceiveJSON reads the HTTP request body. When the return is false then w must be left as is.

func ServeJSON

func ServeJSON(w http.ResponseWriter, statusCode int, src interface{})

ServeJSON writes the HTTP response body.

Types

type CRUDRepo

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

CRUDRepo is a REST repository.

func NewCRUD

func NewCRUD(mountLocation, versionPath string) *CRUDRepo

NewCRUD returns a new REST repository for the CRUD operations. The mountLocation specifies the root for CRUDRepo.ServeHTTP. The versionPath is a GoEL expression to the date version (in the data type).

It's operation is based on two assumptions. 1) Identifiers are int64. 2) Versions are int64 unix timestamps in nanoseconds.

func (*CRUDRepo) ServeHTTP

func (repo *CRUDRepo) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP honors the http.Handler interface for the mount point provided with NewCRUD. For now only JSON is supported.

func (*CRUDRepo) SetCreateFunc

func (repo *CRUDRepo) SetCreateFunc(f interface{})

SetCreateFunc enables create support. The method panics on any of the following conditions. 1) f does not match signature func(data T) (id int64, err error) 2) Data type T does not match the other CRUD operations. 3) Data type T is not a pointer.

It is the responsibility of f to set the version.

Example
package main

import (
	"bytes"
	"fmt"
	"net/http"
	"net/http/httptest"
	"sync/atomic"
	"time"

	"github.com/pascaldekloe/goe/rest"
)

func main() {
	type Data struct {
		Version int64  `json:"version"`
		Msg     string `json:"msg"`
	}
	var v atomic.Value
	v.Store(&Data{})

	repo := rest.NewCRUD("/", "/Version")
	repo.SetCreateFunc(func(d *Data) (int64, error) {
		d.Version = time.Now().UnixNano()
		v.Store(d)
		return 42, nil
	})

	server := httptest.NewServer(repo)
	defer server.Close()

	res, err := http.Post(server.URL, "application/json", bytes.NewBufferString(`{"msg": "Hello World!"}`))
	if err != nil {
		panic(err)
	}
	fmt.Printf("Got HTTP %s %s: %s\n", res.Status, res.Header.Get("Location"), v.Load().(*Data).Msg)

}
Output:

Got HTTP 201 Created /42: Hello World!

func (*CRUDRepo) SetDeleteFunc

func (repo *CRUDRepo) SetDeleteFunc(f interface{})

SetUpdateFunc enables update support. The method panics when f does not match signature func(id, version int64) error.

When the id is not found f must return ErrNotFound. When the version is not equal to 0 and version does not match the latest one available then f must skip normal operation and return ErrOptimisticLock.

func (*CRUDRepo) SetReadFunc

func (repo *CRUDRepo) SetReadFunc(f interface{})

SetReadFunc enables read support. The method panics on any of the following conditions. 1) f does not match signature func(id, version int64) (hit T, err error) 2) Data type T does not match the other CRUD operations. 3) Data type T is not a pointer.

When the id is not found f must return ErrNotFound. The version must be honored and the latest version should be served as a fallback.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/pascaldekloe/goe/rest"
)

func main() {
	type Data struct {
		Version int64  `json:"version"`
		Msg     string `json:"msg"`
	}

	repo := rest.NewCRUD("/", "/Version")
	repo.SetReadFunc(func(id, version int64) (*Data, error) {
		if id != 42 {
			return nil, rest.ErrNotFound
		}
		return &Data{1456260879956532222, "Hello World!"}, nil
	})

	server := httptest.NewServer(repo)
	defer server.Close()

	req, err := http.NewRequest("GET", server.URL+"/42", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("If-None-Match", `"1456260879956532222"`)

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Got HTTP %s: %s\n", res.Status, res.Header.Get("Content-Location"))

}
Output:

Got HTTP 304 Not Modified: /42?v=1456260879956532222

func (*CRUDRepo) SetUpdateFunc

func (repo *CRUDRepo) SetUpdateFunc(f interface{})

SetUpdateFunc enables update support. The method panics on any of the following conditions. 1) f does not match signature func(id int64, data T) (error) 2) Data type T does not match the other CRUD operations. 3) Data type T is not a pointer.

When the id is not found f must return ErrNotFound. When the data's version is not equal to 0 and version does not match the latest one available then f must skip normal operation and return ErrOptimisticLock. It is the responsibility of f to set the new version.

Notes

Bugs

  • No support for multiple entity tags in If-None-Match header.

  • No support for multiple entity tags in If-Match header.

Jump to

Keyboard shortcuts

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