You've already forked openaccounting-server
mirror of
https://github.com/openaccounting/oa-server.git
synced 2025-12-09 09:00:42 +13:00
128 lines
3.8 KiB
Go
128 lines
3.8 KiB
Go
package rest
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"net"
|
|
"net/http"
|
|
)
|
|
|
|
// A ResponseWriter interface dedicated to JSON HTTP response.
|
|
// Note, the responseWriter object instantiated by the framework also implements many other interfaces
|
|
// accessible by type assertion: http.ResponseWriter, http.Flusher, http.CloseNotifier, http.Hijacker.
|
|
type ResponseWriter interface {
|
|
|
|
// Identical to the http.ResponseWriter interface
|
|
Header() http.Header
|
|
|
|
// Use EncodeJson to generate the payload, write the headers with http.StatusOK if
|
|
// they are not already written, then write the payload.
|
|
// The Content-Type header is set to "application/json", unless already specified.
|
|
WriteJson(v interface{}) error
|
|
|
|
// Encode the data structure to JSON, mainly used to wrap ResponseWriter in
|
|
// middlewares.
|
|
EncodeJson(v interface{}) ([]byte, error)
|
|
|
|
// Similar to the http.ResponseWriter interface, with additional JSON related
|
|
// headers set.
|
|
WriteHeader(int)
|
|
}
|
|
|
|
// This allows to customize the field name used in the error response payload.
|
|
// It defaults to "Error" for compatibility reason, but can be changed before starting the server.
|
|
// eg: rest.ErrorFieldName = "errorMessage"
|
|
var ErrorFieldName = "Error"
|
|
|
|
// Error produces an error response in JSON with the following structure, '{"Error":"My error message"}'
|
|
// The standard plain text net/http Error helper can still be called like this:
|
|
// http.Error(w, "error message", code)
|
|
func Error(w ResponseWriter, error string, code int) {
|
|
w.WriteHeader(code)
|
|
err := w.WriteJson(map[string]string{ErrorFieldName: error})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// NotFound produces a 404 response with the following JSON, '{"Error":"Resource not found"}'
|
|
// The standard plain text net/http NotFound helper can still be called like this:
|
|
// http.NotFound(w, r.Request)
|
|
func NotFound(w ResponseWriter, r *Request) {
|
|
Error(w, "Resource not found", http.StatusNotFound)
|
|
}
|
|
|
|
// Private responseWriter intantiated by the resource handler.
|
|
// It implements the following interfaces:
|
|
// ResponseWriter
|
|
// http.ResponseWriter
|
|
// http.Flusher
|
|
// http.CloseNotifier
|
|
// http.Hijacker
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
wroteHeader bool
|
|
}
|
|
|
|
func (w *responseWriter) WriteHeader(code int) {
|
|
if w.Header().Get("Content-Type") == "" {
|
|
// Per spec, UTF-8 is the default, and the charset parameter should not
|
|
// be necessary. But some clients (eg: Chrome) think otherwise.
|
|
// Since json.Marshal produces UTF-8, setting the charset parameter is a
|
|
// safe option.
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
}
|
|
w.ResponseWriter.WriteHeader(code)
|
|
w.wroteHeader = true
|
|
}
|
|
|
|
func (w *responseWriter) EncodeJson(v interface{}) ([]byte, error) {
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// Encode the object in JSON and call Write.
|
|
func (w *responseWriter) WriteJson(v interface{}) error {
|
|
b, err := w.EncodeJson(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = w.Write(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Provided in order to implement the http.ResponseWriter interface.
|
|
func (w *responseWriter) Write(b []byte) (int, error) {
|
|
if !w.wroteHeader {
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
return w.ResponseWriter.Write(b)
|
|
}
|
|
|
|
// Provided in order to implement the http.Flusher interface.
|
|
func (w *responseWriter) Flush() {
|
|
if !w.wroteHeader {
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|
|
flusher := w.ResponseWriter.(http.Flusher)
|
|
flusher.Flush()
|
|
}
|
|
|
|
// Provided in order to implement the http.CloseNotifier interface.
|
|
func (w *responseWriter) CloseNotify() <-chan bool {
|
|
notifier := w.ResponseWriter.(http.CloseNotifier)
|
|
return notifier.CloseNotify()
|
|
}
|
|
|
|
// Provided in order to implement the http.Hijacker interface.
|
|
func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|
hijacker := w.ResponseWriter.(http.Hijacker)
|
|
return hijacker.Hijack()
|
|
}
|