func (res *Resource) addRoute(method string, route string) {
	res.Routes = append(res.Routes, fmt.Sprintf("%s - /%s%s", method, res.Type, route))
}
addRoute adds the new method and route to a route Tree for debugging and
informational purposes.
package jshapi
import (
	"fmt"
	"net/http"
	"path"
	"reflect"
	"strings"
	"goji.io"
	"goji.io/pat"
	"github.com/derekdowling/go-json-spec-handler"
	"github.com/derekdowling/go-json-spec-handler/jsh-api/store"
)
const (
	post    = "POST"
	get     = "GET"
	list    = "LIST"
	delete  = "DELETE"
	patch   = "PATCH"
	patID   = "/:id"
	patRoot = ""
)
type Resource struct {
	*goji.Mux
	Type string
	Routes []string
	Relationships map[string]Relationship
}
func NewResource(resourceType string) *Resource {
	return &Resource{
		Mux: goji.SubMux(),
		Type:          resourceType,
		Relationships: map[string]Relationship{},
		Routes: []string{},
	}
}
func NewCRUDResource(resourceType string, storage store.CRUD) *Resource {
	resource := NewResource(resourceType)
	resource.CRUD(storage)
	return resource
}
func (res *Resource) CRUD(storage store.CRUD) {
	res.Get(storage.Get)
	res.Patch(storage.Update)
	res.Post(storage.Save)
	res.List(storage.List)
	res.Delete(storage.Delete)
}
func (res *Resource) Post(storage store.Save) {
	res.HandleFunc(
		pat.Post(patRoot),
		func(w http.ResponseWriter, r *http.Request) {
			res.postHandler(w, r, storage)
		},
	)
	res.addRoute(post, patRoot)
}
func (res *Resource) Get(storage store.Get) {
	res.HandleFunc(
		pat.Get(patID),
		func(w http.ResponseWriter, r *http.Request) {
			res.getHandler(w, r, storage)
		},
	)
	res.addRoute(get, patID)
}
func (res *Resource) List(storage store.List) {
	res.HandleFunc(
		pat.Get(patRoot),
		func(w http.ResponseWriter, r *http.Request) {
			res.listHandler(w, r, storage)
		},
	)
	res.addRoute(get, patRoot)
}
func (res *Resource) Delete(storage store.Delete) {
	res.HandleFunc(
		pat.Delete(patID),
		func(w http.ResponseWriter, r *http.Request) {
			res.deleteHandler(w, r, storage)
		},
	)
	res.addRoute(delete, patID)
}
func (res *Resource) Patch(storage store.Update) {
	res.HandleFunc(
		pat.Patch(patID),
		func(w http.ResponseWriter, r *http.Request) {
			res.patchHandler(w, r, storage)
		},
	)
	res.addRoute(patch, patID)
}
func (res *Resource) ToOne(
	resourceType string,
	storage store.Get,
) {
	resourceType = strings.TrimSuffix(resourceType, "s")
	res.relationshipHandler(
		resourceType,
		func(w http.ResponseWriter, r *http.Request) {
			res.getHandler(w, r, storage)
		},
	)
	res.Relationships[resourceType] = ToOne
}
func (res *Resource) ToMany(
	resourceType string,
	storage store.ToMany,
) {
	if !strings.HasSuffix(resourceType, "s") {
		resourceType = fmt.Sprintf("%ss", resourceType)
	}
	res.relationshipHandler(
		resourceType,
		func(w http.ResponseWriter, r *http.Request) {
			res.toManyHandler(w, r, storage)
		},
	)
	res.Relationships[resourceType] = ToMany
}
func (res *Resource) relationshipHandler(
	resourceType string,
	handler http.HandlerFunc,
) {
	matcher := fmt.Sprintf("%s/%s", patID, resourceType)
	res.HandleFunc(
		pat.Get(matcher),
		handler,
	)
	res.addRoute(get, matcher)
	relationshipMatcher := fmt.Sprintf("%s/relationships/%s", patID, resourceType)
	res.HandleFunc(
		pat.Get(relationshipMatcher),
		handler,
	)
	res.addRoute(get, relationshipMatcher)
}
func (res *Resource) Action(actionName string, storage store.Get) {
	matcher := path.Join(patID, actionName)
	res.HandleFunc(
		pat.Get(matcher),
		func(w http.ResponseWriter, r *http.Request) {
			res.actionHandler(w, r, storage)
		},
	)
	res.addRoute(patch, matcher)
}
func (res *Resource) postHandler(w http.ResponseWriter, r *http.Request, storage store.Save) {
	parsedObject, parseErr := jsh.ParseObject(r)
	if parseErr != nil && reflect.ValueOf(parseErr).IsNil() == false {
		SendHandler(w, r, parseErr)
		return
	}
	object, err := storage(r.Context(), parsedObject)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, object)
}
func (res *Resource) getHandler(w http.ResponseWriter, r *http.Request, storage store.Get) {
	id := pat.Param(r, "id")
	object, err := storage(r.Context(), id)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, object)
}
func (res *Resource) listHandler(w http.ResponseWriter, r *http.Request, storage store.List) {
	list, err := storage(r.Context())
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, list)
}
func (res *Resource) deleteHandler(w http.ResponseWriter, r *http.Request, storage store.Delete) {
	id := pat.Param(r, "id")
	err := storage(r.Context(), id)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	w.WriteHeader(http.StatusNoContent)
}
func (res *Resource) patchHandler(w http.ResponseWriter, r *http.Request, storage store.Update) {
	parsedObject, parseErr := jsh.ParseObject(r)
	if parseErr != nil && reflect.ValueOf(parseErr).IsNil() == false {
		SendHandler(w, r, parseErr)
		return
	}
	id := pat.Param(r, "id")
	if id != parsedObject.ID {
		SendHandler(w, r, jsh.InputError("Request ID does not match URL's", "id"))
		return
	}
	object, err := storage(r.Context(), parsedObject)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, object)
}
func (res *Resource) toManyHandler(w http.ResponseWriter, r *http.Request, storage store.ToMany) {
	id := pat.Param(r, "id")
	list, err := storage(r.Context(), id)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, list)
}
func (res *Resource) actionHandler(w http.ResponseWriter, r *http.Request, storage store.Get) {
	id := pat.Param(r, "id")
	response, err := storage(r.Context(), id)
	if err != nil && reflect.ValueOf(err).IsNil() == false {
		SendHandler(w, r, err)
		return
	}
	SendHandler(w, r, response)
}