handlers.*LemonsqueezyHandler.handleRequest   C
last analyzed

Complexity

Conditions 10

Size

Total Lines 33
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 29
dl 0
loc 33
rs 5.9999
c 0
b 0
f 0
nop 2

How to fix   Complexity   

Complexity

Complex classes like handlers.*LemonsqueezyHandler.handleRequest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package handlers
2
3
import (
4
	"context"
5
	"encoding/json"
6
	"fmt"
7
8
	"github.com/NdoleStudio/httpsms/pkg/services"
9
	"github.com/NdoleStudio/httpsms/pkg/telemetry"
10
	"github.com/NdoleStudio/httpsms/pkg/validators"
11
	lemonsqueezy "github.com/NdoleStudio/lemonsqueezy-go"
12
	"github.com/davecgh/go-spew/spew"
13
	"github.com/gofiber/fiber/v2"
14
	"github.com/palantir/stacktrace"
15
)
16
17
// LemonsqueezyHandler handles lemonsqueezy events
18
type LemonsqueezyHandler struct {
19
	handler
20
	logger    telemetry.Logger
21
	tracer    telemetry.Tracer
22
	service   *services.LemonsqueezyService
23
	validator *validators.LemonsqueezyHandlerValidator
24
}
25
26
// NewLemonsqueezyHandler creates a new LemonsqueezyHandler
27
func NewLemonsqueezyHandler(
28
	logger telemetry.Logger,
29
	tracer telemetry.Tracer,
30
	service *services.LemonsqueezyService,
31
	validator *validators.LemonsqueezyHandlerValidator,
32
) (h *LemonsqueezyHandler) {
33
	return &LemonsqueezyHandler{
34
		logger:    logger.WithService(fmt.Sprintf("%T", h)),
35
		tracer:    tracer,
36
		service:   service,
37
		validator: validator,
38
	}
39
}
40
41
// RegisterRoutes registers the routes for the MessageHandler
42
func (h *LemonsqueezyHandler) RegisterRoutes(app *fiber.App, middlewares ...fiber.Handler) {
43
	router := app.Group("lemonsqueezy")
44
	router.Post("/event", h.computeRoute(middlewares, h.Event)...)
45
}
46
47
// Event consumes a lemonsqueezy event
48
// @Summary      Consume a lemonsqueezy event
49
// @Description  Publish a lemonsqueezy event to the registered listeners
50
// @Tags         Lemonsqueezy
51
// @Accept       json
52
// @Produce      json
53
// @Success      204 		{object}	responses.NoContent
54
// @Failure      400		{object}	responses.BadRequest
55
// @Failure 	 401    	{object}	responses.Unauthorized
56
// @Failure      422		{object}	responses.UnprocessableEntity
57
// @Failure      500		{object}	responses.InternalServerError
58
// @Router       /lemonsqueezy/event [post]
59
func (h *LemonsqueezyHandler) Event(c *fiber.Ctx) error {
60
	ctx, span, ctxLogger := h.tracer.StartFromFiberCtxWithLogger(c, h.logger)
61
	defer span.End()
62
63
	signature := c.Get("X-Signature")
64
	if errors := h.validator.ValidateEvent(ctx, signature, c.Body()); len(errors) != 0 {
65
		msg := fmt.Sprintf("validation errors [%s], while storing request [%s] and signature [%s]", spew.Sdump(errors), c.Body(), signature)
66
		ctxLogger.Warn(stacktrace.NewError(msg))
67
		return h.responseUnprocessableEntity(c, errors, "validation errors while storing lemonsqueezy event")
68
	}
69
70
	if err := h.handleRequest(ctx, c); err != nil {
71
		msg := fmt.Sprintf("cannot handle lemonsqueezy event [%s]", c.Body())
72
		ctxLogger.Error(stacktrace.Propagate(err, msg))
73
		return h.responseInternalServerError(c)
74
	}
75
76
	return h.responseNoContent(c, "event consumed successfully")
77
}
78
79
func (h *LemonsqueezyHandler) handleRequest(ctx context.Context, c *fiber.Ctx) error {
80
	eventName := c.Get("X-Event-Name")
81
	switch eventName {
82
	case "subscription_created":
83
		var request lemonsqueezy.WebhookRequestSubscription
84
		err := json.Unmarshal(c.Body(), &request)
85
		if err != nil {
86
			return stacktrace.Propagate(err, fmt.Sprintf("cannot marshall [%s] to [%T]", c.Body(), request))
87
		}
88
		return h.service.HandleSubscriptionCreatedEvent(ctx, c.OriginalURL(), &request)
89
	case "subscription_cancelled":
90
		var request lemonsqueezy.WebhookRequestSubscription
91
		err := json.Unmarshal(c.Body(), &request)
92
		if err != nil {
93
			return stacktrace.Propagate(err, fmt.Sprintf("cannot marshall [%s] to [%T]", c.Body(), request))
94
		}
95
		return h.service.HandleSubscriptionCanceledEvent(ctx, c.OriginalURL(), &request)
96
	case "subscription_expired":
97
		var request lemonsqueezy.WebhookRequestSubscription
98
		err := json.Unmarshal(c.Body(), &request)
99
		if err != nil {
100
			return stacktrace.Propagate(err, fmt.Sprintf("cannot marshall [%s] to [%T]", c.Body(), request))
101
		}
102
		return h.service.HandleSubscriptionExpiredEvent(ctx, c.OriginalURL(), &request)
103
	case "subscription_updated":
104
		var request lemonsqueezy.WebhookRequestSubscription
105
		err := json.Unmarshal(c.Body(), &request)
106
		if err != nil {
107
			return stacktrace.Propagate(err, fmt.Sprintf("cannot marshall [%s] to [%T]", c.Body(), request))
108
		}
109
		return h.service.HandleSubscriptionUpdatedEvent(ctx, c.OriginalURL(), &request)
110
	default:
111
		return stacktrace.NewError(fmt.Sprintf("invalid event [%s] received with request [%s]", eventName, c.Body()))
112
	}
113
}
114