-
-
Notifications
You must be signed in to change notification settings - Fork 163
/
Copy pathmain.go
93 lines (82 loc) · 3 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package main
import (
"net/http"
"os"
echoadapter "github.com/awslabs/aws-lambda-go-api-proxy/echo"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
custommiddleware "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/api/middleware"
"github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/log"
"github.com/thomaspoignant/go-feature-flag/internal/flag"
"github.com/thomaspoignant/go-feature-flag/internal/utils"
"github.com/thomaspoignant/go-feature-flag/model"
"github.com/thomaspoignant/go-feature-flag/model/dto"
)
// This service is an API used to evaluate a flag with an evaluation context
// This API is made for the Flag Editor to be able to evaluate a flag remotely and see if the configuration
// of the flag is working as expected.
func main() {
logger := log.InitLogger()
defer func() { _ = logger.ZapLogger.Sync() }()
e := echo.New()
e.Use(custommiddleware.ZapLogger(logger.ZapLogger, nil))
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{
"http://gofeatureflag.org",
"https://gofeatureflag.org",
"http://www.gofeatureflag.org",
"https://www.gofeatureflag.org",
},
AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
}))
g := e.Group("/v1")
g.POST("/feature/evaluate", EvaluateHandler)
e.GET("/health", HealthHandler)
if _, exists := os.LookupEnv("RUN_AS_LAMBDA"); exists {
adapter := awsLambdaHandler{adapter: echoadapter.NewV2(e)}
adapter.Start()
} else {
e.Logger.Fatal(e.Start(":1323"))
}
}
// EvaluateHandler is the function called when calling the endpoint /v1/feature/evaluate.
// It will perform a flag evaluation and return the resolutionDetails and the value.
func EvaluateHandler(c echo.Context) error {
u := new(editorEvaluateRequest)
if err := c.Bind(u); err != nil {
return err
}
f := u.Flag.Convert()
value, resolutionDetails := f.Value(
u.FlagName,
utils.ConvertEvaluationCtxFromRequest(u.Context.Key, u.Context.Custom),
flag.Context{
DefaultSdkValue: nil,
},
)
resp := model.VariationResult[interface{}]{
Value: value,
VariationType: resolutionDetails.Variant,
Reason: resolutionDetails.Reason,
ErrorCode: resolutionDetails.ErrorCode,
Failed: resolutionDetails.ErrorCode != "",
Cacheable: resolutionDetails.Cacheable,
Metadata: f.GetMetadata(),
}
return c.JSON(http.StatusOK, resp)
}
// HealthHandler endpoint to validate that the service is up and running.
func HealthHandler(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
// editorEvaluateRequest is the format expected to receive from the editor to test the flag.
type editorEvaluateRequest struct {
Context ContextWrapper `json:"context,omitempty"`
Flag dto.DTO `json:"flag,omitempty"`
FlagName string `json:"flagName,omitempty"`
}
// ContextWrapper is a struct to migrate the API request to an actual evaluation context.
type ContextWrapper struct {
Key string `json:"key,omitempty"`
Custom map[string]interface{}
}