5
5
"errors"
6
6
"fmt"
7
7
daoErr "github.com/go-feature-flag/app-api/dao/err"
8
+ "github.com/go-feature-flag/app-api/util"
8
9
"github.com/labstack/echo/v4"
9
10
"net/http"
10
11
"time"
@@ -15,14 +16,25 @@ import (
15
16
"github.com/lib/pq"
16
17
)
17
18
19
+ type FlagAPIHandlerOptions struct {
20
+ Clock util.Clock
21
+ }
22
+
18
23
type FlagAPIHandler struct {
19
- dao dao.Flags
24
+ dao dao.Flags
25
+ options * FlagAPIHandlerOptions
20
26
}
21
27
22
28
// NewFlagAPIHandler creates a new instance of the FlagAPIHandler handler
23
29
// It is a controller class to handle the feature flag configuration logic
24
- func NewFlagAPIHandler (dao dao.Flags ) FlagAPIHandler {
25
- return FlagAPIHandler {dao : dao }
30
+ func NewFlagAPIHandler (dao dao.Flags , options * FlagAPIHandlerOptions ) FlagAPIHandler {
31
+ if options == nil {
32
+ options = & FlagAPIHandlerOptions {}
33
+ }
34
+ if options .Clock == nil {
35
+ options .Clock = util.DefaultClock {}
36
+ }
37
+ return FlagAPIHandler {dao : dao , options : options }
26
38
}
27
39
28
40
// GetAllFeatureFlags is returning the list of all the flags
@@ -87,8 +99,8 @@ func (f FlagAPIHandler) CreateNewFlag(c echo.Context) error {
87
99
if flag .ID == "" {
88
100
flag .ID = uuid .NewString ()
89
101
}
90
- flag .CreatedDate = time .Now ()
91
- flag .LastUpdatedDate = time .Now ()
102
+ flag .CreatedDate = f . options . Clock .Now ()
103
+ flag .LastUpdatedDate = f . options . Clock .Now ()
92
104
// TODO: remove this line and extract the information from the token
93
105
flag .LastModifiedBy = "toto"
94
106
@@ -105,6 +117,9 @@ func (f FlagAPIHandler) CreateNewFlag(c echo.Context) error {
105
117
106
118
id , err := f .dao .CreateFlag (c .Request ().Context (), flag )
107
119
if err != nil {
120
+ if err .Code () == daoErr .ConversionError {
121
+ return c .JSON (model .NewHTTPError (http .StatusBadRequest , err ))
122
+ }
108
123
return c .JSON (model .NewHTTPError (http .StatusInternalServerError , err ))
109
124
}
110
125
flag .ID = id
@@ -123,8 +138,17 @@ func validateFlag(flag model.FeatureFlag) (int, error) {
123
138
return status , err
124
139
}
125
140
126
- if flag .VariationType == "" {
141
+ switch flag .VariationType {
142
+ case model .FlagTypeBoolean ,
143
+ model .FlagTypeDouble ,
144
+ model .FlagTypeInteger ,
145
+ model .FlagTypeString ,
146
+ model .FlagTypeJSON :
147
+ break
148
+ case "" :
127
149
return http .StatusBadRequest , errors .New ("flag type is required" )
150
+ default :
151
+ return http .StatusBadRequest , fmt .Errorf ("flag type %s not supported" , flag .VariationType )
128
152
}
129
153
130
154
for _ , rule := range flag .GetRules () {
@@ -137,10 +161,15 @@ func validateFlag(flag model.FeatureFlag) (int, error) {
137
161
}
138
162
139
163
func validateRule (rule * model.Rule , isDefault bool ) (int , error ) {
140
- if rule == nil ||
141
- (rule .ProgressiveRollout == nil &&
142
- rule .Percentages == nil &&
143
- (rule .VariationResult == nil || * rule .VariationResult == "" )) {
164
+ if rule == nil || * rule == (model.Rule {}) {
165
+ if isDefault {
166
+ return http .StatusBadRequest , errors .New ("flag default rule is required" )
167
+ }
168
+ return http .StatusBadRequest , errors .New ("targeting rule is nil" )
169
+ }
170
+ if rule .ProgressiveRollout == nil &&
171
+ rule .Percentages == nil &&
172
+ (rule .VariationResult == nil || * rule .VariationResult == "" ) {
144
173
err := fmt .Errorf ("invalid rule %s" , rule .Name )
145
174
if isDefault {
146
175
err = errors .New ("flag default rule is invalid" )
@@ -150,7 +179,7 @@ func validateRule(rule *model.Rule, isDefault bool) (int, error) {
150
179
151
180
if ! isDefault {
152
181
if rule .Query == "" {
153
- return http .StatusBadRequest , errors .New ("rule query is required" )
182
+ return http .StatusBadRequest , errors .New ("query is required for targeting rules " )
154
183
}
155
184
}
156
185
return http .StatusOK , nil
@@ -263,7 +292,7 @@ func (f FlagAPIHandler) UpdateFeatureFlagStatus(c echo.Context) error {
263
292
func (f FlagAPIHandler ) handleDaoError (c echo.Context , err daoErr.DaoError ) error {
264
293
switch err .Code () {
265
294
case daoErr .NotFound :
266
- return c .JSON (model .NewHTTPError (http .StatusNotFound , fmt .Errorf ("flag with id %s not found" , c . Param ( "id" ) )))
295
+ return c .JSON (model .NewHTTPError (http .StatusNotFound , fmt .Errorf ("flag not found" )))
267
296
case daoErr .InvalidUUID :
268
297
return c .JSON (model .NewHTTPError (http .StatusBadRequest , fmt .Errorf ("invalid UUID format" )))
269
298
default :
0 commit comments