replace the fiber framework with net/http.ServeMux

This commit is contained in:
2025-12-23 13:33:05 +01:00
parent 5a705b0af0
commit 37c7e808ed
7 changed files with 241 additions and 152 deletions

View File

@@ -1,4 +1,4 @@
.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42)
.\" .\"
.\" Standard preamble: .\" Standard preamble:
.\" ======================================================================== .\" ========================================================================
@@ -133,7 +133,7 @@
.\" ======================================================================== .\" ========================================================================
.\" .\"
.IX Title "ANYDB 1" .IX Title "ANYDB 1"
.TH ANYDB 1 "2025-02-11" "1" "User Commands" .TH ANYDB 1 "2025-11-03" "1" "User Commands"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents. .\" way too many mistakes in technical documents.
.if n .ad l .if n .ad l

View File

@@ -19,11 +19,15 @@ package cfg
import ( import (
"fmt" "fmt"
"io" "io"
"log/slog"
"os" "os"
"runtime/debug"
"github.com/pelletier/go-toml"
"codeberg.org/scip/anydb/app" "codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/common" "codeberg.org/scip/anydb/common"
"github.com/lmittmann/tint"
"github.com/pelletier/go-toml"
"github.com/tlinden/yadu"
) )
var Version string = "v0.2.6" var Version string = "v0.2.6"
@@ -58,6 +62,8 @@ func (conf *Config) GetConfig(files []string) error {
} }
} }
conf.SetLogger()
return nil return nil
} }
@@ -114,3 +120,36 @@ func (conf *Config) ParseConfigFile(file string) error {
return nil return nil
} }
func (conf *Config) SetLogger() {
if conf.Debug {
buildInfo, _ := debug.ReadBuildInfo()
opts := &yadu.Options{
Level: slog.LevelDebug,
AddSource: true,
}
slog.SetLogLoggerLevel(slog.LevelDebug)
handler := yadu.NewHandler(os.Stdout, opts)
debuglogger := slog.New(handler).With(
slog.Group("program_info",
slog.Int("pid", os.Getpid()),
slog.String("go_version", buildInfo.GoVersion),
),
)
slog.SetDefault(debuglogger)
slog.Debug("parsed config", "conf", conf)
} else {
opts := &tint.Options{
Level: slog.LevelInfo,
AddSource: false,
}
handler := tint.NewHandler(os.Stderr, opts)
logger := slog.New(handler)
slog.SetDefault(logger)
}
}

8
go.mod
View File

@@ -6,8 +6,8 @@ toolchain go1.24.1
require ( require (
github.com/dustin/go-humanize v1.0.1 github.com/dustin/go-humanize v1.0.1
github.com/gofiber/fiber/v2 v2.52.9
github.com/inconshreveable/mousetrap v1.1.0 github.com/inconshreveable/mousetrap v1.1.0
github.com/lmittmann/tint v1.1.2
github.com/olekukonko/tablewriter v1.1.0 github.com/olekukonko/tablewriter v1.1.0
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/rogpeppe/go-internal v1.14.1 github.com/rogpeppe/go-internal v1.14.1
@@ -20,10 +20,7 @@ require (
) )
require ( require (
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
@@ -31,9 +28,6 @@ require (
github.com/olekukonko/ll v0.0.9 // indirect github.com/olekukonko/ll v0.0.9 // indirect
github.com/rivo/uniseg v0.2.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/spf13/pflag v1.0.9 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.55.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.36.0 // indirect golang.org/x/sys v0.36.0 // indirect
golang.org/x/tools v0.26.0 // indirect golang.org/x/tools v0.26.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

18
go.sum
View File

@@ -1,5 +1,3 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -7,16 +5,12 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -46,14 +40,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY= github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA= github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=

View File

@@ -19,7 +19,9 @@ package rest
import ( import (
//"github.com/alecthomas/repr" //"github.com/alecthomas/repr"
"github.com/gofiber/fiber/v2" "encoding/json"
"net/http"
"codeberg.org/scip/anydb/app" "codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg" "codeberg.org/scip/anydb/cfg"
) )
@@ -40,101 +42,95 @@ type SingleResponse struct {
Entry *app.DbEntry Entry *app.DbEntry
} }
func RestList(c *fiber.Ctx, conf *cfg.Config) error { func RestList(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
attr := new(app.DbAttr) attr := new(app.DbAttr)
if len(c.Body()) > 0 { err := json.NewDecoder(req.Body).Decode(&attr)
if err := c.BodyParser(attr); err != nil { if err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{ if err.Error() != `EOF` {
"errors": err.Error(), http.Error(resp, err.Error(), http.StatusBadRequest)
}) return
} }
} }
// get list // get list
entries, err := conf.DB.List(attr, attr.Fulltext) entries, err := conf.DB.List(attr, attr.Fulltext)
if err != nil { if err != nil {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "Unable to list keys: "+err.Error())
"Unable to list keys: "+err.Error()) return
} }
return c.Status(fiber.StatusOK).JSON( resp.Header().Set("Content-Type", "application/json")
json.NewEncoder(resp).Encode(
ListResponse{ ListResponse{
Code: http.StatusOK,
Success: true, Success: true,
Code: fiber.StatusOK,
Entries: entries, Entries: entries,
}, })
)
} }
func RestGet(c *fiber.Ctx, conf *cfg.Config) error { func RestGet(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
if c.Params("key") == "" { if key == "" {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "key not provided")
"key not provided") return
} }
// get list // get list
entry, err := conf.DB.Get(&app.DbAttr{Key: c.Params("key")}) entry, err := conf.DB.Get(&app.DbAttr{Key: key})
if err != nil { if err != nil {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "Unable to get key: "+err.Error())
"Unable to get key: "+err.Error()) return
} }
if entry.Key == "" { if entry.Key == "" {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "Key does not exist")
"Key does not exist") return
} }
return c.Status(fiber.StatusOK).JSON( resp.Header().Set("Content-Type", "application/json")
json.NewEncoder(resp).Encode(
SingleResponse{ SingleResponse{
Code: http.StatusOK,
Success: true, Success: true,
Code: fiber.StatusOK,
Entry: entry, Entry: entry,
}, })
)
} }
func RestDelete(c *fiber.Ctx, conf *cfg.Config) error { func RestDelete(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
if c.Params("key") == "" { if key == "" {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "key not provided")
"key not provided") return
} }
// get list // get list
err := conf.DB.Del(&app.DbAttr{Key: c.Params("key")}) err := conf.DB.Del(&app.DbAttr{Key: key})
if err != nil { if err != nil {
return JsonStatus(c, fiber.StatusForbidden, JsonStatus(resp, http.StatusForbidden, "Unable to delete key: "+err.Error())
"Unable to delete key: "+err.Error()) return
} }
return c.Status(fiber.StatusOK).JSON( JsonStatus(resp, http.StatusOK, "key deleted")
Result{
Success: true,
Code: fiber.StatusOK,
Message: "key deleted",
},
)
} }
func RestSet(c *fiber.Ctx, conf *cfg.Config) error { func RestSet(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
attr := new(app.DbAttr) attr := new(app.DbAttr)
if err := c.BodyParser(attr); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
"errors": err.Error(),
})
} err := json.NewDecoder(req.Body).Decode(&attr)
err := conf.DB.Set(attr)
if err != nil { if err != nil {
return JsonStatus(c, fiber.StatusForbidden, http.Error(resp, err.Error(), http.StatusBadRequest)
"Unable to set key: "+err.Error()) return
} }
return c.Status(fiber.StatusOK).JSON( err = conf.DB.Set(attr)
Result{ if err != nil {
Success: true, JsonStatus(resp, http.StatusForbidden, "Unable to set key: "+err.Error())
Code: fiber.StatusOK, return
}, }
)
JsonStatus(resp, http.StatusOK, "key added/updated")
}
func Home(resp http.ResponseWriter) {
resp.Write([]byte("Use the REST API on " + apiprefix + "\r\n"))
} }

100
rest/log.go Normal file
View File

@@ -0,0 +1,100 @@
/*
This logging middleware is based on
https://github.com/elithrar/admission-control/blob/v0.6.3/request_logger.go
by Matt Silverlock licensed under the Apache-2.0 license.
I am using slog and added a couple of small modifications.
*/
package rest
import (
"log/slog"
"net/http"
"runtime/debug"
"time"
)
// responseWriter is a minimal wrapper for http.ResponseWriter that allows the
// written HTTP status code to be captured for logging.
type responseWriter struct {
http.ResponseWriter
status int
size int
wroteHeader bool
}
func wrapResponseWriter(w http.ResponseWriter) *responseWriter {
return &responseWriter{ResponseWriter: w}
}
func (rw *responseWriter) Status() int {
return rw.status
}
func (rw *responseWriter) Size() int {
return rw.size
}
func (rw *responseWriter) WriteHeader(code int) {
if rw.wroteHeader {
return
}
rw.status = code
rw.ResponseWriter.WriteHeader(code)
rw.wroteHeader = true
return
}
func (rw *responseWriter) Write(data []byte) (int, error) {
written, err := rw.ResponseWriter.Write(data)
rw.size += written
return written, err
}
// LoggingMiddleware logs the incoming HTTP request & its duration.
func LogHandler() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(resp http.ResponseWriter, req *http.Request) {
defer func() {
if err := recover(); err != nil {
resp.WriteHeader(http.StatusInternalServerError)
slog.Info(
"internal server error",
"err", err,
"trace", string(debug.Stack()),
)
}
}()
start := time.Now()
wrapped := wrapResponseWriter(resp)
next.ServeHTTP(wrapped, req)
header := wrapped.Header()["Content-Type"]
contenttype := ""
if header == nil {
contenttype = "text/plain"
} else {
contenttype = header[0]
}
slog.Info("request",
"ip", req.RemoteAddr,
"status", wrapped.status,
"method", req.Method,
"path", req.URL.EscapedPath(),
"size", wrapped.Size(),
"content-type", contenttype,
"duration", time.Since(start),
)
}
return http.HandlerFunc(fn)
}
}

View File

@@ -17,10 +17,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package rest package rest
import ( import (
"github.com/gofiber/fiber/v2" "encoding/json"
"github.com/gofiber/fiber/v2/middleware/compress" "net/http"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"codeberg.org/scip/anydb/cfg" "codeberg.org/scip/anydb/cfg"
) )
@@ -31,84 +30,59 @@ type Result struct {
Code int `json:"code"` Code int `json:"code"`
} }
const apiprefix = `/anydb/v1/`
func Runserver(conf *cfg.Config, args []string) error { func Runserver(conf *cfg.Config, args []string) error {
// setup api server // setup api server
router := SetupServer(conf) mux := http.NewServeMux()
// public rest api routes mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
api := router.Group("/anydb/v1") Home(w)
{
api.Get("/", func(c *fiber.Ctx) error {
return RestList(c, conf)
}) })
api.Post("/", func(c *fiber.Ctx) error { mux.HandleFunc("GET "+apiprefix, func(w http.ResponseWriter, r *http.Request) {
// same thing as above but allows to supply parameters, see app.Dbattr{} RestList(w, r, conf)
return RestList(c, conf)
}) })
api.Get("/:key", func(c *fiber.Ctx) error { mux.HandleFunc("POST "+apiprefix, func(w http.ResponseWriter, r *http.Request) {
return RestGet(c, conf) RestList(w, r, conf)
}) })
api.Delete("/:key", func(c *fiber.Ctx) error { mux.HandleFunc("GET "+apiprefix+"{key}", func(w http.ResponseWriter, r *http.Request) {
return RestDelete(c, conf) key := r.PathValue("key")
RestGet(w, r, key, conf)
}) })
api.Put("/", func(c *fiber.Ctx) error { mux.HandleFunc("DELETE "+apiprefix+"{key}", func(w http.ResponseWriter, r *http.Request) {
return RestSet(c, conf) key := r.PathValue("key")
}) RestDelete(w, r, key, conf)
}
// public routes
{
router.Get("/", func(c *fiber.Ctx) error {
return c.Send([]byte("Use the REST API"))
})
}
return router.Listen(conf.Listen)
}
func SetupServer(conf *cfg.Config) *fiber.App {
// disable colors
fiber.DefaultColors = fiber.Colors{}
router := fiber.New(fiber.Config{
CaseSensitive: true,
StrictRouting: true,
Immutable: true,
ServerHeader: "anydb serve",
AppName: "anydb",
}) })
router.Use(logger.New(logger.Config{ mux.HandleFunc("PUT "+apiprefix, func(w http.ResponseWriter, r *http.Request) {
Format: "${pid} ${ip}:${port} ${status} - ${method} ${path}\n", RestList(w, r, conf)
DisableColors: true, })
}))
router.Use(cors.New(cors.Config{ logger := LogHandler()
AllowMethods: "GET,PUT,POST,DELETE",
ExposeHeaders: "Content-Type,Accept",
}))
router.Use(compress.New(compress.Config{ return http.ListenAndServe(conf.Listen, logger(mux))
Level: compress.LevelBestSpeed,
}))
return router
} }
/* /*
Wrapper to respond with proper json status, message and code, Wrapper to respond with proper json status, message and code,
shall be prepared and called by the handlers directly. shall be prepared and called by the handlers directly.
*/ */
func JsonStatus(c *fiber.Ctx, code int, msg string) error { func JsonStatus(resp http.ResponseWriter, code int, msg string) error {
success := code == fiber.StatusOK success := code == http.StatusOK
return c.Status(code).JSON(Result{ resp.Header().Set("Content-Type", "application/json")
resp.WriteHeader(code)
json.NewEncoder(resp).Encode(
Result{
Code: code, Code: code,
Message: msg, Message: msg,
Success: success, Success: success,
}) })
return nil
} }