78 lines
1.6 KiB
Go
78 lines
1.6 KiB
Go
|
package server
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"runtime/debug"
|
||
|
)
|
||
|
|
||
|
type ApiError struct {
|
||
|
Err string
|
||
|
Status int
|
||
|
}
|
||
|
|
||
|
func (e ApiError) Error() string {
|
||
|
return e.Err
|
||
|
}
|
||
|
|
||
|
type apiFunc func(Context) error
|
||
|
|
||
|
func MakeHTTPHandler(f apiFunc) http.HandlerFunc {
|
||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||
|
ctx := Context{w, r}
|
||
|
if err := f(ctx); err != nil {
|
||
|
if e, ok := err.(ApiError); ok {
|
||
|
log.Println("API ERROR: ", e.Error(), e.Status)
|
||
|
ctx.WriteJSON(e.Status, e)
|
||
|
return
|
||
|
}
|
||
|
log.Println("INTERNAL ERROR: ", err)
|
||
|
debug.PrintStack()
|
||
|
ctx.WriteJSON(500, &ApiError{Err: "internal error", Status: http.StatusInternalServerError})
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Context struct {
|
||
|
W http.ResponseWriter
|
||
|
R *http.Request
|
||
|
}
|
||
|
|
||
|
func (c Context) Header(header string, value string) *Context {
|
||
|
c.W.Header().Add(header, value)
|
||
|
return &c
|
||
|
}
|
||
|
|
||
|
func (c Context) ContentType(contentType string) *Context {
|
||
|
return c.Header("Content-Type", contentType)
|
||
|
}
|
||
|
|
||
|
func (c Context) Status(status int) *Context {
|
||
|
c.W.WriteHeader(status)
|
||
|
return &c
|
||
|
}
|
||
|
|
||
|
func (c Context) WriteJSON(status int, v any) error {
|
||
|
c.ContentType("application/json").Status(status)
|
||
|
return json.NewEncoder(c.W).Encode(v)
|
||
|
}
|
||
|
|
||
|
func (c Context) WritePlain(status int, text string) error {
|
||
|
c.ContentType("text/plain").Status(status)
|
||
|
_, err := c.W.Write([]byte(text))
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func (c Context) WriteBlob(status int, contentType string, blob []byte) error {
|
||
|
c.ContentType(contentType).Status(status)
|
||
|
_, err := c.W.Write(blob)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func DecodeJSON(r io.Reader, v any) error {
|
||
|
return json.NewDecoder(r).Decode(v)
|
||
|
}
|