Skip to content

Commit

Permalink
refactor(httpfx): replace Response with ResponseResult for consistency
Browse files Browse the repository at this point in the history
- Updated all instances of `Response` to `ResponseResult` across the HTTP middleware and handler functions.
- Disabled all `revive` linter rules in `.golangci.yaml`.
- Consolidated Makefile and Go-related configurations in `.editorconfig`.
- Replaced hand-written assertion checks with `assert` from `testify`.
- Fixed `StringsTrim*` functions to handle empty inputs correctly.
- Added utility function `SerializeSlogAttrs` in `lib/slog.go`.
- Introduced structured error and result handling in `results` package.
  • Loading branch information
eser committed Aug 22, 2024
1 parent 269d84d commit 31bd12c
Show file tree
Hide file tree
Showing 32 changed files with 339 additions and 147 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ max_line_length = off
[{*.md,*.mdx,*.mdoc}]
trim_trailing_whitespace = false

[Makefile]
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
indent_style = tab
86 changes: 43 additions & 43 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,55 +36,55 @@ linters-settings:
- github.com/getkin/kin-openapi/openapi3
- github.com/golang-jwt/jwt/v5
revive:
enable-all-rules: true
# enable-all-rules: true
ignore-generated-header: true
severity: warning
rules:
- name: var-naming
disabled: true
arguments: []
- name: exported
severity: warning
- name: error-return
severity: warning
- name: error-naming
severity: warning
- name: if-return
severity: warning
- name: var-naming
severity: warning
- name: var-declaration
severity: warning
- name: receiver-naming
severity: warning
- name: errorf
severity: warning
- name: empty-block
severity: warning
- name: unused-parameter
severity: warning
- name: unreachable-code
severity: warning
- name: redefines-builtin-id
severity: warning
- name: superfluous-else
severity: warning
- name: unexported-return
severity: warning
- name: indent-error-flow
severity: warning
- name: blank-imports
severity: warning
- name: range
severity: warning
- name: time-naming
severity: warning
- name: context-as-argument
severity: warning
- name: context-keys-type
severity: warning
- name: indent-error-flow
severity: warning
# - name: exported
# severity: warning
# - name: error-return
# severity: warning
# - name: error-naming
# severity: warning
# - name: if-return
# severity: warning
# - name: var-naming
# severity: warning
# - name: var-declaration
# severity: warning
# - name: receiver-naming
# severity: warning
# - name: errorf
# severity: warning
# - name: empty-block
# severity: warning
# - name: unused-parameter
# severity: warning
# - name: unreachable-code
# severity: warning
# - name: redefines-builtin-id
# severity: warning
# - name: superfluous-else
# severity: warning
# - name: unexported-return
# severity: warning
# - name: indent-error-flow
# severity: warning
# - name: blank-imports
# severity: warning
# - name: range
# severity: warning
# - name: time-naming
# severity: warning
# - name: context-as-argument
# severity: warning
# - name: context-keys-type
# severity: warning
# - name: indent-error-flow
# severity: warning

issues:
fix: true
Expand Down
4 changes: 2 additions & 2 deletions pkg/app/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func RegisterRoutes(routes httpfx.Router, appConfig *AppConfig) {
routes.Use(middlewares.CorsMiddleware())

routes.
Route("GET /", func(ctx *httpfx.Context) httpfx.Response {
Route("GET /", func(ctx *httpfx.Context) httpfx.ResponseResult {
message := fmt.Sprintf(
"Hello %s (%s) from %s!",
ctx.Request.Context().Value(middlewares.ClientAddr),
Expand All @@ -65,7 +65,7 @@ func RegisterRoutes(routes httpfx.Router, appConfig *AppConfig) {
HasResponse(http.StatusOK)

routes.
Route("GET /protected", middlewares.AuthMiddleware(), func(ctx *httpfx.Context) httpfx.Response {
Route("GET /protected", middlewares.AuthMiddleware(), func(ctx *httpfx.Context) httpfx.ResponseResult {
message := fmt.Sprintf("Hello from %s! this endpoint is protected!", appConfig.AppName)

return ctx.Results.PlainText(message)
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Context struct {
// isAborted bool
}

func (c *Context) Next() Response {
func (c *Context) Next() ResponseResult {
c.index++

for c.index < len(c.handlers) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/auth-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
var ErrInvalidSigningMethod = errors.New("Invalid signing method")

func AuthMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
tokenString, hasToken := getBearerToken(ctx)

if !hasToken {
Expand Down
15 changes: 5 additions & 10 deletions pkg/bliss/httpfx/middlewares/auth-middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/eser/go-service/pkg/bliss/httpfx"
"github.com/eser/go-service/pkg/bliss/httpfx/middlewares"
"github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
)

func createToken(secret string, exp time.Time) string {
Expand Down Expand Up @@ -78,24 +79,18 @@ func TestAuthMiddleware(t *testing.T) {
result := middleware(&httpCtx)

if result.StatusCode != tt.expectedStatusCode {
t.Errorf("Expected status code %d, got %d", tt.expectedStatusCode, result.StatusCode)
assert.Equal(t, tt.expectedStatusCode, result.StatusCode)
}

if tt.expectedStatusCode == http.StatusOK || tt.expectedStatusCode == http.StatusNoContent {
claims, claimsOk := httpCtx.Request.Context().Value(middlewares.AuthClaims).(jwt.MapClaims)

if !claimsOk {
t.Error("Claims are missing in context")
}
assert.True(t, claimsOk, "Claims are missing in context")

if claims["exp"] == nil {
t.Error("exp claim is missing")
}
assert.NotNil(t, claims["exp"], "exp claim is missing")

if exp, ok := claims["exp"].(float64); ok {
if time.Unix(int64(exp), 0).Before(time.Now()) {
t.Error("exp claim is not valid")
}
assert.False(t, time.Unix(int64(exp), 0).Before(time.Now()), "exp claim is not valid")
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/correlation-id-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
const CorrelationIdHeader = "X-Correlation-Id"

func CorrelationIdMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
// FIXME(@eser): no need to check if the header is specified
correlationId := ctx.Request.Header.Get(CorrelationIdHeader)
if correlationId == "" {
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/cors-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
const AccessControlAllowOriginHeader = "Access-Control-Allow-Origin"

func CorsMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
result := ctx.Next()

ctx.ResponseWriter.Header().Set(AccessControlAllowOriginHeader, "*")
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/error-handler-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package middlewares
import "github.com/eser/go-service/pkg/bliss/httpfx"

func ErrorHandlerMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
result := ctx.Next()

return result
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/resolve-address-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
)

func ResolveAddressMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
addr := GetClientAddrs(ctx.Request)

newContext := context.WithValue(
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/middlewares/response-time-middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
const ResponseTimeHeader = "X-Request-Time"

func ResponseTimeMiddleware() httpfx.Handler {
return func(ctx *httpfx.Context) httpfx.Response {
return func(ctx *httpfx.Context) httpfx.ResponseResult {
startTime := time.Now()

result := ctx.Next()
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/modules/healthcheck/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var Module = fx.Module( //nolint:gochecknoglobals

func RegisterRoutes(routes httpfx.Router) {
routes.
Route("GET /health-check", func(ctx *httpfx.Context) httpfx.Response {
Route("GET /health-check", func(ctx *httpfx.Context) httpfx.ResponseResult {
return ctx.Results.Ok()
}).
HasSummary("Health Check").
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/modules/openapi/mod.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var Module = fx.Module( //nolint:gochecknoglobals

func RegisterRoutes(routes httpfx.Router) {
routes.
Route("GET /openapi.json", func(ctx *httpfx.Context) httpfx.Response {
Route("GET /openapi.json", func(ctx *httpfx.Context) httpfx.ResponseResult {
spec := &ApiIdentity{
name: "golang-service",
version: "0.0.0",
Expand Down
2 changes: 1 addition & 1 deletion pkg/bliss/httpfx/primitives.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package httpfx

type (
Handler func(*Context) Response
Handler func(*Context) ResponseResult
HandlerChain []Handler
Middleware func() Handler
)
50 changes: 27 additions & 23 deletions pkg/bliss/httpfx/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,55 @@ package httpfx
import (
"encoding/json"
"net/http"

"github.com/eser/go-service/pkg/bliss/results"
)

type Response struct {
type ResponseResult struct {
results.Result

StatusCode int
Body []byte

RedirectToUri string
}

func (r Response) WithStatusCode(statusCode int) Response {
func (r ResponseResult) WithStatusCode(statusCode int) ResponseResult {
r.StatusCode = statusCode

return r
}

func (r Response) WithBody(body string) Response {
func (r ResponseResult) WithBody(body string) ResponseResult {
r.Body = []byte(body)

return r
}

type Results struct{}

func (r *Results) Ok() Response {
return Response{ //nolint:exhaustruct
func (r *Results) Ok() ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusNoContent,
Body: []byte{},
}
}

func (r *Results) Bytes(body []byte) Response {
return Response{ //nolint:exhaustruct
func (r *Results) Bytes(body []byte) ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusOK,
Body: body,
}
}

func (r *Results) PlainText(body string) Response {
return Response{ //nolint:exhaustruct
func (r *Results) PlainText(body string) ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusOK,
Body: []byte(body),
}
}

func (r *Results) Json(body any) Response {
func (r *Results) Json(body any) ResponseResult {
encoded, err := json.Marshal(body)
if err != nil {
// TODO(@eser): Log error
Expand All @@ -57,51 +61,51 @@ func (r *Results) Json(body any) Response {
)
}

return Response{ //nolint:exhaustruct
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusOK,
Body: encoded,
}
}

func (r *Results) Redirect(uri string) Response {
return Response{
func (r *Results) Redirect(uri string) ResponseResult {
return ResponseResult{
StatusCode: http.StatusTemporaryRedirect,
Body: []byte{},
RedirectToUri: uri,
}
}

func (r *Results) NotFound() Response {
return Response{ //nolint:exhaustruct
func (r *Results) NotFound() ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusNotFound,
Body: []byte("Not Found"),
}
}

func (r *Results) Unauthorized(body string) Response {
return Response{ //nolint:exhaustruct
func (r *Results) Unauthorized(body string) ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusUnauthorized,
Body: []byte(body),
}
}

func (r *Results) BadRequest() Response {
return Response{ //nolint:exhaustruct
func (r *Results) BadRequest() ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusBadRequest,
Body: []byte("Bad Request"),
}
}

func (r *Results) Error(statusCode int, message string) Response {
return Response{ //nolint:exhaustruct
func (r *Results) Error(statusCode int, message string) ResponseResult {
return ResponseResult{ //nolint:exhaustruct
StatusCode: statusCode,
Body: []byte(message),
}
}

func (r *Results) Abort() Response {
func (r *Results) Abort() ResponseResult {
// TODO(@eser) implement this
return Response{ //nolint:exhaustruct
return ResponseResult{ //nolint:exhaustruct
StatusCode: http.StatusNotImplemented,
Body: []byte("Not Implemented"),
}
Expand Down
Loading

0 comments on commit 31bd12c

Please sign in to comment.