package rest import ( "net/http" "context" "net/url" "path" ) type contextKey struct { name string } // StatusCtxKey is a context key to record a future HTTP response status code. var StatusCtxKey = &contextKey{"Status"} // Status sets a HTTP response status code hint into request context at any // point during the request life-cycle. Before the Responder sends its response // header it will check the StatusCtxKey func Status(r *http.Request, status int) { *r = *r.WithContext(context.WithValue(r.Context(), StatusCtxKey, status)) } // Location ensures a given HTTP Location header is either an absolute reference // (has a non-empty schema) or relative reference (has no schema nor authority, // but an absolute path). func Location(reference string) string { u, err := url.Parse(reference) if err != nil { panic("rest: invalid location: " + err.Error()) } if u.IsAbs() { return u.String() } // Make sure the relative reference is an "absolute-path reference". u.User = nil u.Host = "" if u.Path != "" && !path.IsAbs(u.Path) { u.Path = "/" + u.Path } return u.String() } // NoContent returns a HTTP 204 "No Content" response. func NoContent(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } // Conflict returns a HTTP 409 "Conflict" response. func Conflict(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusConflict) } // Created returns a HTTP 201 "Created" response. // // It differs from `http.Redirect(w, r, http.StatusCreated, loc)` in that // headers are not stripped. func Created(w http.ResponseWriter, _ *http.Request, loc string) { w.Header().Set("Location", Location(loc)) w.WriteHeader(http.StatusCreated) } // CreatedJSON returns a HTTP 201 "Created" response. // // It differs from `Created` in that it also writes a JSON body. func CreatedJSON(w http.ResponseWriter, r *http.Request, loc string, v interface{}) { w.Header().Set("Location", Location(loc)) Status(r, http.StatusCreated) JSON(w, r, v) }