auth

Paddy 2014-12-14 Parent:5bccbed6631b Child:2e4b5722eed0

104:bc77a315f823 Go to Latest

auth/request.go

Add request helpers. Fix a typo in the requestErrConflict constant. Create a response type that is used to build responses before sending them down the wire. Create vars for a few common types of error responses that never change. Create a negotiate middleware function that will respond with a 406 error if the client requests an encoding that we can't support. Create an encode helper that determines the requested encoding and uses it to send the data down the wire. Move our wrap middleware from the oauth2.go file to the request.go file, where it's more likely to be looked for.

History
paddy@99 1 package auth
paddy@99 2
paddy@104 3 import (
paddy@104 4 "encoding/json"
paddy@104 5 "log"
paddy@104 6 "net/http"
paddy@104 7
paddy@104 8 "bitbucket.org/ww/goautoneg"
paddy@104 9 )
paddy@104 10
paddy@99 11 const (
paddy@99 12 requestErrAccessDenied = "access_denied"
paddy@99 13 requestErrInsufficient = "insufficient"
paddy@99 14 requestErrOverflow = "overflow"
paddy@99 15 requestErrInvalidValue = "invalid_value"
paddy@99 16 requestErrInvalidFormat = "invalid_format"
paddy@99 17 requestErrMissing = "missing"
paddy@99 18 requestErrNotFound = "not_found"
paddy@104 19 requestErrConflict = "conflict"
paddy@99 20 requestErrActOfGod = "act_of_god"
paddy@99 21 )
paddy@99 22
paddy@104 23 var (
paddy@104 24 actOfGodResponse = response{Errors: []requestError{requestError{Slug: requestErrActOfGod}}}
paddy@104 25 invalidFormatResponse = response{Errors: []requestError{requestError{Slug: requestErrInvalidFormat, Field: "/"}}}
paddy@104 26
paddy@104 27 encoders = []string{"application/json"}
paddy@104 28 )
paddy@104 29
paddy@104 30 type response struct {
paddy@104 31 Errors []requestError `json:"errors,omitempty"`
paddy@104 32 Logins []Login `json:"logins,omitempty"`
paddy@104 33 Profiles []Profile `json:"profiles,omitempty"`
paddy@104 34 }
paddy@104 35
paddy@99 36 type requestError struct {
paddy@99 37 Slug string `json:"error,omitempty"`
paddy@99 38 Field string `json:"field,omitempty"`
paddy@99 39 Param string `json:"param,omitempty"`
paddy@99 40 Header string `json:"header,omitempty"`
paddy@99 41 }
paddy@104 42
paddy@104 43 func negotiate(h http.Handler) http.Handler {
paddy@104 44 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@104 45 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@104 46 if contentType == "" {
paddy@104 47 w.WriteHeader(http.StatusNotAcceptable)
paddy@104 48 log.Println("Unsupported Accept header:", r.Header.Get("Accept"))
paddy@104 49 w.Write([]byte("Unsupported content type requested: " + r.Header.Get("Accept")))
paddy@104 50 return
paddy@104 51 }
paddy@104 52 h.ServeHTTP(w, r)
paddy@104 53 })
paddy@104 54 }
paddy@104 55
paddy@104 56 func encode(w http.ResponseWriter, r *http.Request, status int, resp response) {
paddy@104 57 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
paddy@104 58 w.Header().Set("content-type", contentType)
paddy@104 59 w.WriteHeader(status)
paddy@104 60 var err error
paddy@104 61 switch contentType {
paddy@104 62 case "application/json":
paddy@104 63 enc := json.NewEncoder(w)
paddy@104 64 err = enc.Encode(resp)
paddy@104 65 }
paddy@104 66 if err != nil {
paddy@104 67 log.Println(err)
paddy@104 68 }
paddy@104 69 }
paddy@104 70
paddy@104 71 func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
paddy@104 72 return negotiate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
paddy@104 73 f(w, r, context)
paddy@104 74 }))
paddy@104 75 }