diff --git a/api.go b/api.go index a78988a..22945d7 100644 --- a/api.go +++ b/api.go @@ -20,10 +20,10 @@ func GetAlbums(r *http.Request, enc Encoder, db DB) string { } if band != "" || title != "" || yri != 0 { // At least one filter, use Find() - return Must(enc.Encode(toIface(db.Find(band, title, yri))...)) + return Must(enc(toIface(db.Find(band, title, yri))...)) } // Otherwise, return all albums - return Must(enc.Encode(toIface(db.GetAll())...)) + return Must(enc(toIface(db.GetAll())...)) } // GetAlbum returns the requested album. @@ -32,10 +32,10 @@ func GetAlbum(enc Encoder, db DB, parms martini.Params) (int, string) { al := db.Get(id) if err != nil || al == nil { // Invalid id, or does not exist - return http.StatusNotFound, Must(enc.Encode( + return http.StatusNotFound, Must(enc( NewError(ErrCodeNotExist, fmt.Sprintf("the album with id %s does not exist", parms["id"])))) } - return http.StatusOK, Must(enc.Encode(al)) + return http.StatusOK, Must(enc(al)) } // AddAlbum creates the posted album. @@ -45,12 +45,12 @@ func AddAlbum(w http.ResponseWriter, r *http.Request, enc Encoder, db DB) (int, switch err { case ErrAlreadyExists: // Duplicate - return http.StatusConflict, Must(enc.Encode( + return http.StatusConflict, Must(enc( NewError(ErrCodeAlreadyExists, fmt.Sprintf("the album '%s' from '%s' already exists", al.Title, al.Band)))) case nil: // TODO : Location is expected to be an absolute URI, as per the RFC2616 w.Header().Set("Location", fmt.Sprintf("/albums/%d", id)) - return http.StatusCreated, Must(enc.Encode(al)) + return http.StatusCreated, Must(enc(al)) default: panic(err) } @@ -61,16 +61,16 @@ func UpdateAlbum(r *http.Request, enc Encoder, db DB, parms martini.Params) (int al, err := getPutAlbum(r, parms) if err != nil { // Invalid id, 404 - return http.StatusNotFound, Must(enc.Encode( + return http.StatusNotFound, Must(enc( NewError(ErrCodeNotExist, fmt.Sprintf("the album with id %s does not exist", parms["id"])))) } err = db.Update(al) switch err { case ErrAlreadyExists: - return http.StatusConflict, Must(enc.Encode( + return http.StatusConflict, Must(enc( NewError(ErrCodeAlreadyExists, fmt.Sprintf("the album '%s' from '%s' already exists", al.Title, al.Band)))) case nil: - return http.StatusOK, Must(enc.Encode(al)) + return http.StatusOK, Must(enc(al)) default: panic(err) } @@ -110,7 +110,7 @@ func DeleteAlbum(enc Encoder, db DB, parms martini.Params) (int, string) { id, err := strconv.Atoi(parms["id"]) al := db.Get(id) if err != nil || al == nil { - return http.StatusNotFound, Must(enc.Encode( + return http.StatusNotFound, Must(enc( NewError(ErrCodeNotExist, fmt.Sprintf("the album with id %s does not exist", parms["id"])))) } db.Delete(id) diff --git a/encoding.go b/encoding.go index c250ce9..8fdf2fa 100644 --- a/encoding.go +++ b/encoding.go @@ -9,9 +9,8 @@ import ( // An Encoder implements an encoding format of values to be sent as response to // requests on the API endpoints. -type Encoder interface { - Encode(v ...interface{}) (string, error) -} + +type Encoder func(v ...interface{}) (string, error) // Because `panic`s are caught by martini's Recovery handler, it can be used // to return server-side errors (500). Some helpful text message should probably @@ -23,10 +22,8 @@ func Must(data string, err error) string { return data } -type jsonEncoder struct{} - // jsonEncoder is an Encoder that produces JSON-formatted responses. -func (_ jsonEncoder) Encode(v ...interface{}) (string, error) { +var jsonEncoder Encoder = func(v ...interface{}) (string, error) { var data interface{} = v if v == nil { // So that empty results produces `[]` and not `null` @@ -38,10 +35,8 @@ func (_ jsonEncoder) Encode(v ...interface{}) (string, error) { return string(b), err } -type xmlEncoder struct{} - // xmlEncoder is an Encoder that produces XML-formatted responses. -func (_ xmlEncoder) Encode(v ...interface{}) (string, error) { +var xmlEncoder Encoder = func(v ...interface{}) (string, error) { var buf bytes.Buffer if _, err := buf.Write([]byte(xml.Header)); err != nil { return "", err @@ -62,10 +57,8 @@ func (_ xmlEncoder) Encode(v ...interface{}) (string, error) { return buf.String(), nil } -type textEncoder struct{} - // textEncoder is an Encoder that produces plain text-formatted responses. -func (_ textEncoder) Encode(v ...interface{}) (string, error) { +var textEncoder Encoder = func(v ...interface{}) (string, error) { var buf bytes.Buffer for _, v := range v { if _, err := fmt.Fprintf(&buf, "%s\n", v); err != nil { diff --git a/server.go b/server.go index 98334c5..2b4591f 100644 --- a/server.go +++ b/server.go @@ -61,13 +61,13 @@ func MapEncoder(c martini.Context, w http.ResponseWriter, r *http.Request) { // Inject the requested encoder switch ft { case ".xml": - c.MapTo(xmlEncoder{}, (*Encoder)(nil)) + c.Map(xmlEncoder) w.Header().Set("Content-Type", "application/xml") case ".text": - c.MapTo(textEncoder{}, (*Encoder)(nil)) + c.Map(textEncoder) w.Header().Set("Content-Type", "text/plain; charset=utf-8") default: - c.MapTo(jsonEncoder{}, (*Encoder)(nil)) + c.Map(jsonEncoder) w.Header().Set("Content-Type", "application/json") } }