Created
May 22, 2014 19:37
-
-
Save alecthomas/dde4346aeaf330862ca0 to your computer and use it in GitHub Desktop.
Convenient return handler for Martini JSON API calls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ( | |
"encoding/json" | |
"net/http" | |
"reflect" | |
"github.com/codegangsta/inject" | |
"github.com/go-martini/martini" | |
) | |
const ( | |
contentType = "application/json; charset=UTF-8" | |
) | |
type APIResponse struct { | |
S int | |
E string `json:",omitempty"` | |
D interface{} `json:",omitempty"` | |
} | |
// Allows responses from request handles to be in the following form: | |
// | |
// (status, <json-encodable-object>) | |
// (status, error) | |
// | |
func MartiniReturnHandler() martini.ReturnHandler { | |
return func(ctx martini.Context, vals []reflect.Value) { | |
// No return value, we assume the function wrote out the response. | |
if len(vals) == 0 { | |
return | |
} | |
res := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))).Interface().(http.ResponseWriter) | |
// req := ctx.Get(reflect.TypeOf(&http.Request{})).Interface().(*http.Request) | |
var responseVal reflect.Value | |
status := 200 | |
if len(vals) > 1 && vals[0].Kind() == reflect.Int { | |
status = int(vals[0].Int()) | |
responseVal = vals[1] | |
if res.Header().Get("Content-Type") == "" { | |
switch responseVal.Interface().(type) { | |
case []byte: | |
res.Header().Set("Content-Type", "application/octet-stream") | |
case string: | |
res.Header().Set("Content-Type", "text/html; charset=utf-8") | |
case error: | |
res.Header().Set("Content-Type", contentType) | |
default: | |
res.Header().Set("Content-Type", contentType) | |
} | |
} | |
res.WriteHeader(status) | |
} else if len(vals) > 0 { | |
responseVal = vals[0] | |
} | |
if canDeref(responseVal) { | |
responseVal = responseVal.Elem() | |
} | |
enc := json.NewEncoder(res) | |
switch v := responseVal.Interface().(type) { | |
case string: | |
res.Write([]byte(v)) | |
case []byte: | |
res.Write(v) | |
case error: | |
enc.Encode(&APIResponse{ | |
S: status, | |
E: v.Error(), | |
}) | |
default: | |
enc.Encode(&APIResponse{ | |
S: status, | |
D: v, | |
}) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment