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)
}