Documentation
¶
Overview ¶
Package render contains implementations of lit.Response, suitable for responding requests.
JSON responses ¶
For simple JSON responses, one can use the function JSON or their "shortcuts", such as OK, BadRequest or Unauthorized. All of them are constructors for JSONResponse.
204 No Content responses ¶
In a special case, the constructor NoContent returns a NoContentResponse, that does not contain a body.
Redirections ¶
The constructor Redirect can be used to redirect a request. If one wants more granularity, the specific redirection functions are also available, such as Found or PermanentRedirect.
Serving files ¶
The constructor File can be used to serve files. It uses internally the http.ServeFile function.
Streaming ¶
The constructor Stream can be used to serve streams. It uses internally the http.ServeContent function.
Custom responses ¶
In order to create new responses not mapped in this package (or to use Facades), such as a YAML response or a new way of serving streams, one can:
- Create a type that implements the lit.Response interface and use it as the return of a handler;
- Return a lit.ResponseFunc, writing to the http.ResponseWriter directly.
Example (CustomResponse) ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/jvcoutinho/lit" "github.com/jvcoutinho/lit/bind" "github.com/jvcoutinho/lit/render" "github.com/jvcoutinho/lit/validate" "gopkg.in/yaml.v3" ) // YAMLResponse is a lit.Response that prints a YAML formatted-body as response. It sets // the Content-Type header to "application/x-yaml". // // If the response contains a body but its marshalling fails, YAMLResponse responds an Internal Server Error // with the error message as plain text. type YAMLResponse struct { StatusCode int Header http.Header Body any } // YAML responds the request with statusCode and a body marshalled as YAML. Nil body equals empty body. // // If body is a string or an error, YAML marshals render.Message with the body assigned to render.Message.Value. // Otherwise, it marshals the body as is. func YAML(statusCode int, body any) YAMLResponse { switch cast := body.(type) { case string: return YAMLResponse{statusCode, make(http.Header), render.Message{Message: cast}} case error: return YAMLResponse{statusCode, make(http.Header), render.Message{Message: cast.Error()}} default: return YAMLResponse{statusCode, make(http.Header), cast} } } func (r YAMLResponse) Write(w http.ResponseWriter) { responseHeader := w.Header() for key := range r.Header { responseHeader.Set(key, r.Header.Get(key)) } if r.Body == nil { w.WriteHeader(r.StatusCode) return } w.Header().Set("Content-Type", "application/x-yaml") if err := r.writeBody(w); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } func (r YAMLResponse) writeBody(w http.ResponseWriter) error { bodyBytes, err := yaml.Marshal(r.Body) if err != nil { return err } w.WriteHeader(r.StatusCode) _, err = w.Write(bodyBytes) return err } type Request struct { A int `query:"a"` B int `query:"b"` } func (r *Request) Validate() []validate.Field { return []validate.Field{ validate.NotEqual(&r.B, 0), } } func Divide(r *lit.Request) lit.Response { req, err := bind.Query[Request](r) if err != nil { return YAML(http.StatusBadRequest, err) } return YAML(http.StatusOK, req.A/req.B) } func main() { r := lit.NewRouter() r.GET("/div", Divide) res := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/div?a=4&b=2", nil) r.ServeHTTP(res, req) fmt.Println(res.Body) res = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/div?a=2&b=0", nil) r.ServeHTTP(res, req) fmt.Println(res.Body) }
Output: 2 message: b should not be equal to 0
Example (Redirecting) ¶
package main import ( "fmt" "net/http" "net/http/httptest" "github.com/jvcoutinho/lit" "github.com/jvcoutinho/lit/render" ) func DeprecatedHelloWorld(r *lit.Request) lit.Response { return render.PermanentRedirect(r, "/new") } func HelloWorld(_ *lit.Request) lit.Response { return render.OK("Hello, World!") } func main() { r := lit.NewRouter() r.GET("/", DeprecatedHelloWorld) r.GET("/new", HelloWorld) res := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/", nil) r.ServeHTTP(res, req) fmt.Println(res.Header(), res.Code) fmt.Println(res.Body) }
Output: map[Content-Type:[text/html; charset=utf-8] Location:[/new]] 308 <a href="/new">Permanent Redirect</a>.
Example (ServingFiles) ¶
package main import ( "fmt" "log" "net/http" "net/http/httptest" "os" "github.com/jvcoutinho/lit" "github.com/jvcoutinho/lit/render" ) var f *os.File func ServeFile(r *lit.Request) lit.Response { return render.File(r, f.Name()) } func main() { f = createTempFile() defer os.Remove(f.Name()) r := lit.NewRouter() r.GET("/file", ServeFile) res := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/file", nil) r.ServeHTTP(res, req) fmt.Println(res.Body) } func createTempFile() *os.File { f, err := os.CreateTemp("", "test_file") if err != nil { log.Fatal(err) } if _, err := f.Write([]byte("content")); err != nil { log.Fatal(err) } if err := f.Close(); err != nil { log.Fatal(err) } return f }
Output: content
Example (Streaming) ¶
package main import ( "fmt" "net/http" "net/http/httptest" "strings" "github.com/jvcoutinho/lit" "github.com/jvcoutinho/lit/render" ) func Stream(r *lit.Request) lit.Response { streamContent := strings.NewReader("streaming content") return render.Stream(r, streamContent) } func main() { r := lit.NewRouter() r.GET("/stream", Stream) res := httptest.NewRecorder() req := httptest.NewRequest(http.MethodGet, "/stream", nil) r.ServeHTTP(res, req) fmt.Println(res.Body) fmt.Println(res.Header()) res = httptest.NewRecorder() req = httptest.NewRequest(http.MethodGet, "/stream", nil) req.Header.Set("If-Match", "tag") r.ServeHTTP(res, req) fmt.Println(res.Body) }
Output: streaming content map[Accept-Ranges:[bytes] Content-Length:[17] Content-Type:[text/plain; charset=utf-8]]
Index ¶
- type FileResponse
- type JSONResponse
- func Accepted(body any) JSONResponse
- func BadRequest(body any) JSONResponse
- func Conflict(body any) JSONResponse
- func Created(body any, locationURL string) JSONResponse
- func Forbidden(body any) JSONResponse
- func InternalServerError(body any) JSONResponse
- func JSON(statusCode int, body any) JSONResponse
- func NotFound(body any) JSONResponse
- func OK(body any) JSONResponse
- func Unauthorized(body any) JSONResponse
- func UnprocessableContent(body any) JSONResponse
- type Message
- type NoContentResponse
- type RedirectResponse
- func Found(r *lit.Request, locationURL string) RedirectResponse
- func MovedPermanently(r *lit.Request, locationURL string) RedirectResponse
- func PermanentRedirect(r *lit.Request, locationURL string) RedirectResponse
- func Redirect(r *lit.Request, locationURL string, permanent, preserveMethod bool) RedirectResponse
- func SeeOther(r *lit.Request, locationURL string) RedirectResponse
- func TemporaryRedirect(r *lit.Request, locationURL string) RedirectResponse
- type StreamResponse
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FileResponse ¶
FileResponse is a lit.Response that sends small chunks of data of a given file.
If the file does not exist, FileResponse responds the request with 404 Not Found.
func File ¶
func File(r *lit.Request, path string) FileResponse
File responds the request with a stream of the contents of a file or directory in path (absolute or relative to the current directory).
If the file does not exist, File responds the request with 404 Not Found.
func (FileResponse) Write ¶
func (r FileResponse) Write(w http.ResponseWriter)
type JSONResponse ¶
JSONResponse is a lit.Response that prints a JSON formatted-body as response. It sets the Content-Type header to "application/json".
If the response contains a body but its marshalling fails, JSON responds an Internal Server Error with the error message as plain text.
func Accepted ¶
func Accepted(body any) JSONResponse
Accepted responds the request with 202 Accepted and a body marshalled as JSON.
func BadRequest ¶
func BadRequest(body any) JSONResponse
BadRequest responds the request with 400 Bad Request and a body marshalled as JSON.
func Conflict ¶
func Conflict(body any) JSONResponse
Conflict responds the request with 409 Conflict and a body marshalled as JSON.
func Created ¶
func Created(body any, locationURL string) JSONResponse
Created responds the request with 201 Created, a body marshalled as JSON and the URL of the created resource in the Location header.
func Forbidden ¶
func Forbidden(body any) JSONResponse
Forbidden responds the request with 403 Forbidden and a body marshalled as JSON.
func InternalServerError ¶
func InternalServerError(body any) JSONResponse
InternalServerError responds the request with 500 Internal Server Error and a body marshalled as JSON.
func JSON ¶
func JSON(statusCode int, body any) JSONResponse
JSON responds the request with statusCode and a body marshalled as JSON. Nil body equals empty body.
If body is a string or an error, JSON marshals Message with the body assigned to Message.Value. Otherwise, it marshals the body as is.
func NotFound ¶
func NotFound(body any) JSONResponse
NotFound responds the request with 404 Not Found and a body marshalled as JSON.
func OK ¶
func OK(body any) JSONResponse
OK responds the request with 200 OK and a body marshalled as JSON.
func Unauthorized ¶
func Unauthorized(body any) JSONResponse
Unauthorized responds the request with 401 Unauthorized and a body marshalled as JSON.
func UnprocessableContent ¶
func UnprocessableContent(body any) JSONResponse
UnprocessableContent responds the request with 422 Unprocessable Content and a body marshalled as JSON.
func (JSONResponse) WithHeader ¶
func (r JSONResponse) WithHeader(key, value string) JSONResponse
WithHeader sets the response header entries associated with key to value.
func (JSONResponse) Write ¶
func (r JSONResponse) Write(w http.ResponseWriter)
type Message ¶
type Message struct { // Content of the message. Message string `json:"message"` }
Message is a standard response for strings and errors.
type NoContentResponse ¶
NoContentResponse is a lit.Response without a body and status code 204 No Content.
func NoContent ¶
func NoContent() NoContentResponse
NoContent responds the request with 204 No Content.
func (NoContentResponse) WithHeader ¶
func (r NoContentResponse) WithHeader(key, value string) NoContentResponse
WithHeader sets the response header entries associated with key to value.
func (NoContentResponse) Write ¶
func (r NoContentResponse) Write(w http.ResponseWriter)
type RedirectResponse ¶
RedirectResponse is a lit.Response that performs redirects.
func Found ¶
func Found(r *lit.Request, locationURL string) RedirectResponse
Found responds the request with 302 Found and a target URL (absolute or relative to the request path) in the Location header.
func MovedPermanently ¶
func MovedPermanently(r *lit.Request, locationURL string) RedirectResponse
MovedPermanently responds the request with 301 Moved Permanently and a target URL (absolute or relative to the request path) in the Location header.
func PermanentRedirect ¶
func PermanentRedirect(r *lit.Request, locationURL string) RedirectResponse
PermanentRedirect responds the request with [307 Permanent Redirect] and a target URL (absolute or relative to the request path) in the Location header.
func Redirect ¶
func Redirect(r *lit.Request, locationURL string, permanent, preserveMethod bool) RedirectResponse
Redirect responds the request with a redirection status code and a target URL (absolute or relative to the request path) in the Location header.
- If permanent is true and preserveMethod is false, it responds with 301 Moved Permanently.
- If permanent is false and preserveMethod is false, it responds with 302 Found.
- If permanent is false and preserveMethod is true, it responds with 307 Temporary Redirect.
- If permanent is true and preserveMethod is true, it responds with 308 Permanent Redirect.
func SeeOther ¶
func SeeOther(r *lit.Request, locationURL string) RedirectResponse
SeeOther responds the request with 303 See Other and a target URL (absolute or relative to the request path) in the Location header.
func TemporaryRedirect ¶
func TemporaryRedirect(r *lit.Request, locationURL string) RedirectResponse
TemporaryRedirect responds the request with 307 Temporary Redirect and a target URL (absolute or relative to the request path) in the Location header.
func (RedirectResponse) Write ¶
func (r RedirectResponse) Write(w http.ResponseWriter)
type StreamResponse ¶
type StreamResponse struct { Request *lit.Request Content io.ReadSeeker FilePath string LastModified time.Time }
StreamResponse is a lit.Response that sends separated small chunks of data from a given content.
func Stream ¶
func Stream(r *lit.Request, content io.ReadSeeker) StreamResponse
Stream responds the request with a stream, sending smaller chunks of a possibly large data.
func (StreamResponse) WithFilePath ¶
func (r StreamResponse) WithFilePath(filePath string) StreamResponse
WithFilePath sets the file path property of the stream. If it is set, StreamResponse uses its extension to derive the Content-Type header, falling back to the stream content otherwise or if it fails.
func (StreamResponse) WithLastModified ¶
func (r StreamResponse) WithLastModified(lastModified time.Time) StreamResponse
WithLastModified sets the last modified property of the stream. If it is set, StreamResponse includes it in the Last-Modified header and, if the request contains an If-Modified-Since header, it uses its value to decide whether the content needs to be sent at all.
func (StreamResponse) Write ¶
func (r StreamResponse) Write(w http.ResponseWriter)