x/rest/collection.go
2020-08-22 15:33:18 -07:00

108 lines
2.9 KiB
Go
Executable File

package rest
import (
"net/http"
"net/url"
"path/filepath"
"sync"
"github.com/jchenry/x/encoding"
)
type CollectionStore interface {
All(params map[string][]string) (interface{}, error)
Get(id string) (interface{}, error)
Delete(id string) error
Update(e interface{}) error
New(e interface{}) error
}
// Example: Collection(p, c, JSONEncoder, json.Decode(func()interface{}{return &foo{}}))
// type Decoder func(io.Reader) (interface{}, error)
func Collection(pool *sync.Pool, store CollectionStore, encode EntityEncoder, decode encoding.Decoder) http.HandlerFunc {
return EntityHandler(
collectionGet(store, encode),
collectionPost(store, encode, decode, pool),
collectionPut(store, encode, decode, pool),
collectionDelete(store, encode),
)
}
func collectionGet(store CollectionStore, encode EntityEncoder) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { // GET
if id := filepath.Base(r.URL.Path); id != "" {
if e, err := store.Get(id); err == nil { // handle individual entity
encode(w, e)
} else {
w.WriteHeader(http.StatusInternalServerError)
encode(w, err)
}
} else {
if params, err := url.ParseQuery(r.URL.RawQuery); err == nil {
if e, err := store.All(params); err == nil { // handle all entities
encode(w, e)
} else {
// TODO: we really should write a header here, but need to figure out what it should be
w.WriteHeader(http.StatusInternalServerError)
}
} else {
// encode(w, err)
w.WriteHeader(http.StatusBadRequest)
}
}
}
}
func collectionPost(store CollectionStore, encode EntityEncoder, decode encoding.Decoder, pool *sync.Pool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { // POST TODO
e := pool.New()
defer pool.Put(e)
if err := decode(r.Body, e); err == nil {
if err = store.New(e); err == nil {
w.WriteHeader(http.StatusCreated)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
} else {
w.WriteHeader(http.StatusBadRequest)
}
}
}
func collectionPut(store CollectionStore, encode EntityEncoder, decode encoding.Decoder, pool *sync.Pool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { // PUT TODO
e := pool.New()
defer pool.Put(e)
if err := decode(r.Body, e); err == nil {
if err = store.Update(e); err == nil {
w.WriteHeader(http.StatusAccepted)
encode(w, e)
} else {
w.WriteHeader(http.StatusInternalServerError)
encode(w, err)
}
} else {
w.WriteHeader(http.StatusBadRequest)
encode(w, err)
}
}
}
func collectionDelete(store CollectionStore, encode EntityEncoder) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { // DELETE TODO
if id := filepath.Base(r.URL.Path); id != "" {
if err := store.Delete(id); err == nil {
w.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusInternalServerError)
}
} else {
w.WriteHeader(http.StatusBadRequest)
}
}
}