From e427851b5bcf60f176b2a18f79a0ced1ac064f0a Mon Sep 17 00:00:00 2001 From: Jonas Tranberg Date: Mon, 12 Apr 2021 17:33:05 +0200 Subject: [PATCH] Refactor the rest server structure (#33) --- cmd/serve.go | 4 ++-- internal/rest/server.go | 29 ++++------------------------- internal/rest/v1/context.go | 13 ------------- internal/rest/v1/project.go | 25 ++++++++++++------------- internal/rest/v1/routes.go | 36 ++++++++++++++++++++++++++++++++++-- 5 files changed, 52 insertions(+), 55 deletions(-) delete mode 100644 internal/rest/v1/context.go diff --git a/cmd/serve.go b/cmd/serve.go index 001b2ac..8275f9c 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -30,9 +30,9 @@ import ( "github.com/spf13/viper" "github.com/uniwise/parrot/internal/cache" "github.com/uniwise/parrot/internal/metrics" - "github.com/uniwise/parrot/pkg/poedit" "github.com/uniwise/parrot/internal/project" "github.com/uniwise/parrot/internal/rest" + "github.com/uniwise/parrot/pkg/poedit" ) const ( @@ -82,7 +82,7 @@ by caching exports from poeditor`, svc := project.NewService(cli, c, viper.GetDuration(confCacheRenewalThreshold), logrus.NewEntry(logger)) - server, err := rest.NewServer(svc, logrus.NewEntry(logger), viper.GetBool(confPrometheusEnabled)) + server, err := rest.NewServer(logrus.NewEntry(logger), svc, viper.GetBool(confPrometheusEnabled)) if err != nil { logger.Fatal(err) } diff --git a/internal/rest/server.go b/internal/rest/server.go index b06e1db..166e303 100644 --- a/internal/rest/server.go +++ b/internal/rest/server.go @@ -6,12 +6,10 @@ import ( gosundheit "github.com/AppsFlyer/go-sundheit" healthhttp "github.com/AppsFlyer/go-sundheit/http" - "github.com/labstack/gommon/random" "github.com/pkg/errors" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" - eprom "github.com/paulfarver/echo-pack/middleware" "github.com/sirupsen/logrus" "github.com/uniwise/parrot/internal/project" v1 "github.com/uniwise/parrot/internal/rest/v1" @@ -19,45 +17,26 @@ import ( const ( gzipCompressionLevel = 5 - requestIDLength = 10 ) type Server struct { Echo *echo.Echo } -func NewServer(projectService project.Service, entry *logrus.Entry, enablePrometheus bool) (*Server, error) { +func NewServer(l *logrus.Entry, projectService project.Service, enablePrometheus bool) (*Server, error) { e := echo.New() + e.HideBanner = true e.HidePort = true e.Validator = NewValidator() - // Middleware e.Use(middleware.Recover()) + e.Use(middleware.RequestID()) e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Level: gzipCompressionLevel, })) - e.Use(middleware.RequestIDWithConfig(middleware.RequestIDConfig{ - Generator: func() string { - return random.String(requestIDLength, random.Hex) - }, - })) - v1Group := e.Group("/v1", func(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - cc := &v1.Context{ - Context: c, - ProjectService: projectService, - Log: entry.WithField("requestID", c.Response().Header().Get(echo.HeaderXRequestID)), - } - - return next(cc) - } - }) - if enablePrometheus { - v1Group.Use(eprom.Prometheus()) - } - v1.Register(v1Group) + v1.Register(e, l, projectService, enablePrometheus) h := gosundheit.New() diff --git a/internal/rest/v1/context.go b/internal/rest/v1/context.go deleted file mode 100644 index 0d40729..0000000 --- a/internal/rest/v1/context.go +++ /dev/null @@ -1,13 +0,0 @@ -package v1 - -import ( - "github.com/labstack/echo/v4" - "github.com/sirupsen/logrus" - "github.com/uniwise/parrot/internal/project" -) - -type Context struct { - echo.Context - ProjectService project.Service - Log *logrus.Entry -} diff --git a/internal/rest/v1/project.go b/internal/rest/v1/project.go index 017f972..f68f07f 100644 --- a/internal/rest/v1/project.go +++ b/internal/rest/v1/project.go @@ -18,22 +18,21 @@ type getProjectLanguageRequest struct { Format string `query:"format" validate:"omitempty,oneof=po pot mo xls xlsx csv ini resw resx android_strings apple_strings xliff properties key_value_json json yml xlf xmb xtb arb rise_360_xliff"` } -func getProjectLanguage(ctx echo.Context) error { - c := ctx.(*Context) - +func (h *Handlers) getProjectLanguage(ctx echo.Context, l *logrus.Entry) error { req := new(getProjectLanguageRequest) - if err := c.Bind(req); err != nil { - c.Log.WithError(err).Error("Error binding request") + if err := ctx.Bind(req); err != nil { + l.WithError(err).Error("Error binding request") return echo.ErrBadRequest } - l := c.Log.WithFields(logrus.Fields{ + l = l.WithFields(logrus.Fields{ "project": req.Project, "language": req.Language, "format": req.Format, }) - if err := c.Validate(req); err != nil { + + if err := ctx.Validate(req); err != nil { l.WithError(err).Error("Error validating request") return echo.ErrBadRequest @@ -51,7 +50,7 @@ func getProjectLanguage(ctx echo.Context) error { return echo.ErrBadRequest } - trans, err := c.ProjectService.GetTranslation( + trans, err := h.ProjectService.GetTranslation( ctx.Request().Context(), req.Project, req.Language, @@ -74,10 +73,10 @@ func getProjectLanguage(ctx echo.Context) error { } } - c.Response().Header().Add("Etag", trans.Checksum) - c.Response().Header().Add("Cache-Control", fmt.Sprintf("max-age=%.0f", trans.TTL.Seconds())) - c.Response().Header().Add("Content-Disposition", fmt.Sprintf("filename=%d-%s.%s", req.Project, req.Language, contentMeta.Extension)) - c.Response().Header().Add("Content-Transfer-Encoding", "8bit") + ctx.Response().Header().Add("Etag", trans.Checksum) + ctx.Response().Header().Add("Cache-Control", fmt.Sprintf("max-age=%.0f", trans.TTL.Seconds())) + ctx.Response().Header().Add("Content-Disposition", fmt.Sprintf("filename=%d-%s.%s", req.Project, req.Language, contentMeta.Extension)) + ctx.Response().Header().Add("Content-Transfer-Encoding", "8bit") - return c.Stream(http.StatusOK, contentMeta.Type, bytes.NewReader(trans.Data)) + return ctx.Stream(http.StatusOK, contentMeta.Type, bytes.NewReader(trans.Data)) } diff --git a/internal/rest/v1/routes.go b/internal/rest/v1/routes.go index 58cdf6d..8509ac2 100644 --- a/internal/rest/v1/routes.go +++ b/internal/rest/v1/routes.go @@ -2,8 +2,40 @@ package v1 import ( "github.com/labstack/echo/v4" + eprom "github.com/paulfarver/echo-pack/middleware" + "github.com/sirupsen/logrus" + "github.com/uniwise/parrot/internal/project" ) -func Register(g *echo.Group) { - g.GET("/project/:project/language/:language", getProjectLanguage) +type Handlers struct { + ProjectService project.Service +} + +type HandlerFunction func(ctx echo.Context, l *logrus.Entry) error + +func Register(e *echo.Echo, l *logrus.Entry, projectService project.Service, enablePrometheus bool) { + h := &Handlers{ + ProjectService: projectService, + } + + g := e.Group("/v1") + + if enablePrometheus { + g.Use(eprom.Prometheus()) + } + + g.GET("/project/:project/language/:language", wrap(h.getProjectLanguage, l)) + +} + +func wrap(fn HandlerFunction, logger *logrus.Entry) echo.HandlerFunc { + return func(ctx echo.Context) error { + l := logger.WithFields(logrus.Fields{ + "method": ctx.Request().Method, + "path": ctx.Request().URL.Path, + "requestId": ctx.Response().Header().Get(echo.HeaderXRequestID), + }) + + return fn(ctx, l) + } }