flipper-api 0.10.2 → 0.11.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/flipper-api.gemspec +12 -12
- data/lib/flipper/api/action.rb +12 -10
- data/lib/flipper/api/action_collection.rb +2 -2
- data/lib/flipper/api/error_response.rb +9 -8
- data/lib/flipper/api/json_params.rb +45 -0
- data/lib/flipper/api/middleware.rb +3 -28
- data/lib/flipper/api/v1/actions/actors_gate.rb +1 -9
- data/lib/flipper/api/v1/actions/boolean_gate.rb +1 -1
- data/lib/flipper/api/v1/actions/clear_feature.rb +21 -0
- data/lib/flipper/api/v1/actions/feature.rb +8 -16
- data/lib/flipper/api/v1/actions/features.rb +26 -8
- data/lib/flipper/api/v1/actions/groups_gate.rb +18 -7
- data/lib/flipper/api/v1/actions/percentage_of_actors_gate.rb +6 -24
- data/lib/flipper/api/v1/actions/percentage_of_time_gate.rb +6 -23
- data/lib/flipper/api/v1/decorators/feature.rb +3 -4
- data/lib/flipper/api.rb +11 -27
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/api/action_spec.rb +30 -36
- data/spec/flipper/api/json_params_spec.rb +81 -0
- data/spec/flipper/api/v1/actions/actors_gate_spec.rb +33 -22
- data/spec/flipper/api/v1/actions/boolean_gate_spec.rb +2 -2
- data/spec/flipper/api/v1/actions/clear_feature_spec.rb +27 -0
- data/spec/flipper/api/v1/actions/feature_spec.rb +28 -30
- data/spec/flipper/api/v1/actions/features_spec.rb +79 -44
- data/spec/flipper/api/v1/actions/groups_gate_spec.rb +92 -10
- data/spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb +62 -24
- data/spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb +34 -15
- data/spec/flipper/api_spec.rb +55 -0
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c14f137259ca4f58e82fa3ed35b32dd1f0375cb3
|
4
|
+
data.tar.gz: 6ed6d5173f602c198cc7b41e7cc2ac72c9fac096
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffaf1fefc28654784568f600a17f0506a4d0833e4de153aedf89ced7b06613d6a9b7468d400afbdeabf762fd26ca50128140301abeb0e06df1c25c5ed3ef1b0e
|
7
|
+
data.tar.gz: 419c2e26875d8973e7c37d8e1258f1fed26809b1d8798cb692d468f79b5de51599ef57205b4309401198e8bd211d891ddaeb6ed244ecdeae6997883c1d4880e0
|
data/flipper-api.gemspec
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
require File.expand_path('../lib/flipper/version', __FILE__)
|
3
3
|
|
4
|
-
flipper_api_files = lambda
|
5
|
-
file =~
|
6
|
-
|
4
|
+
flipper_api_files = lambda do |file|
|
5
|
+
file =~ %r{(flipper)[\/-]api}
|
6
|
+
end
|
7
7
|
|
8
8
|
Gem::Specification.new do |gem|
|
9
|
-
gem.authors = [
|
10
|
-
gem.email = [
|
11
|
-
gem.summary =
|
12
|
-
gem.description =
|
13
|
-
gem.license =
|
14
|
-
gem.homepage =
|
15
|
-
gem.files = `git ls-files`.split("\n").select(&flipper_api_files) + [
|
9
|
+
gem.authors = ['John Nunemaker']
|
10
|
+
gem.email = ['nunemaker@gmail.com']
|
11
|
+
gem.summary = 'API for the Flipper gem'
|
12
|
+
gem.description = 'Rack middleware that provides an API for the flipper gem.'
|
13
|
+
gem.license = 'MIT'
|
14
|
+
gem.homepage = 'https://github.com/jnunemaker/flipper'
|
15
|
+
gem.files = `git ls-files`.split("\n").select(&flipper_api_files) + ['lib/flipper/version.rb']
|
16
16
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").select(&flipper_api_files)
|
17
|
-
gem.name =
|
18
|
-
gem.require_paths = [
|
17
|
+
gem.name = 'flipper-api'
|
18
|
+
gem.require_paths = ['lib']
|
19
19
|
gem.version = Flipper::VERSION
|
20
20
|
|
21
21
|
gem.add_dependency 'rack', '>= 1.4', '< 3'
|
data/lib/flipper/api/action.rb
CHANGED
@@ -9,11 +9,11 @@ module Flipper
|
|
9
9
|
extend Forwardable
|
10
10
|
|
11
11
|
VALID_REQUEST_METHOD_NAMES = Set.new([
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
'get'.freeze,
|
13
|
+
'post'.freeze,
|
14
|
+
'put'.freeze,
|
15
|
+
'delete'.freeze,
|
16
|
+
]).freeze
|
17
17
|
|
18
18
|
# Public: Call this in subclasses so the action knows its route.
|
19
19
|
#
|
@@ -50,9 +50,10 @@ module Flipper
|
|
50
50
|
def_delegator :@request, :params
|
51
51
|
|
52
52
|
def initialize(flipper, request)
|
53
|
-
@flipper
|
53
|
+
@flipper = flipper
|
54
|
+
@request = request
|
54
55
|
@code = 200
|
55
|
-
@headers = {
|
56
|
+
@headers = { 'Content-Type' => Api::CONTENT_TYPE }
|
56
57
|
end
|
57
58
|
|
58
59
|
# Public: Runs the request method for the provided request.
|
@@ -62,7 +63,8 @@ module Flipper
|
|
62
63
|
if valid_request_method? && respond_to?(request_method_name)
|
63
64
|
catch(:halt) { send(request_method_name) }
|
64
65
|
else
|
65
|
-
raise Api::RequestMethodNotSupported,
|
66
|
+
raise Api::RequestMethodNotSupported,
|
67
|
+
"#{self.class} does not support request method #{request_method_name.inspect}"
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -135,9 +137,9 @@ module Flipper
|
|
135
137
|
end
|
136
138
|
|
137
139
|
# Private: split request path by "/"
|
138
|
-
# Example: "
|
140
|
+
# Example: "features/feature_name" => ['features', 'feature_name']
|
139
141
|
def path_parts
|
140
|
-
@request.path.split(
|
142
|
+
@request.path.split('/')
|
141
143
|
end
|
142
144
|
|
143
145
|
def valid_request_method?
|
@@ -7,7 +7,8 @@ module Flipper
|
|
7
7
|
def initialize(code, message, http_status)
|
8
8
|
@code = code
|
9
9
|
@message = message
|
10
|
-
@more_info =
|
10
|
+
@more_info =
|
11
|
+
'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference'
|
11
12
|
@http_status = http_status
|
12
13
|
end
|
13
14
|
|
@@ -21,13 +22,13 @@ module Flipper
|
|
21
22
|
end
|
22
23
|
|
23
24
|
ERRORS = {
|
24
|
-
feature_not_found: Error.new(1,
|
25
|
-
group_not_registered: Error.new(2,
|
26
|
-
percentage_invalid:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
feature_not_found: Error.new(1, 'Feature not found.', 404),
|
26
|
+
group_not_registered: Error.new(2, 'Group not registered.', 404),
|
27
|
+
percentage_invalid:
|
28
|
+
Error.new(3, 'Percentage must be a positive number less than or equal to 100.', 422),
|
29
|
+
flipper_id_invalid: Error.new(4, 'Required parameter flipper_id is missing.', 422),
|
30
|
+
name_invalid: Error.new(5, 'Required parameter name is missing.', 422),
|
31
|
+
}.freeze
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
|
3
|
+
module Flipper
|
4
|
+
module Api
|
5
|
+
class JsonParams
|
6
|
+
include Rack::Utils
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
CONTENT_TYPE = 'CONTENT_TYPE'.freeze
|
13
|
+
QUERY_STRING = 'QUERY_STRING'.freeze
|
14
|
+
REQUEST_BODY = 'rack.input'.freeze
|
15
|
+
|
16
|
+
# Public: Merge request body params with query string params
|
17
|
+
# This way can access all params with Rack::Request#params
|
18
|
+
# Rack does not add application/json params to Rack::Request#params
|
19
|
+
# Allows app to handle x-www-url-form-encoded / application/json request
|
20
|
+
# parameters the same way
|
21
|
+
def call(env)
|
22
|
+
if env[CONTENT_TYPE] == 'application/json'
|
23
|
+
body = env[REQUEST_BODY].read
|
24
|
+
env[REQUEST_BODY].rewind
|
25
|
+
update_params(env, body)
|
26
|
+
end
|
27
|
+
@app.call(env)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Rails 3.2.2.1 Rack version does not have Rack::Request#update_param
|
33
|
+
# Rack 1.5.0 adds update_param
|
34
|
+
# This method accomplishes similar functionality
|
35
|
+
def update_params(env, data)
|
36
|
+
return if data.empty?
|
37
|
+
parsed_request_body = JSON.parse(data)
|
38
|
+
parsed_query_string = parse_query(env[QUERY_STRING])
|
39
|
+
parsed_query_string.merge!(parsed_request_body)
|
40
|
+
parameters = build_query(parsed_query_string)
|
41
|
+
env[QUERY_STRING] = parameters
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -9,45 +9,20 @@ end
|
|
9
9
|
module Flipper
|
10
10
|
module Api
|
11
11
|
class Middleware
|
12
|
-
|
13
|
-
#
|
14
|
-
# app - The app this middleware is included in.
|
15
|
-
# flipper_or_block - The Flipper::DSL instance or a block that yields a
|
16
|
-
# Flipper::DSL instance to use for all operations.
|
17
|
-
#
|
18
|
-
# Examples
|
19
|
-
#
|
20
|
-
# flipper = Flipper.new(...)
|
21
|
-
#
|
22
|
-
# # using with a normal flipper instance
|
23
|
-
# use Flipper::Api::Middleware, flipper
|
24
|
-
#
|
25
|
-
# # using with a block that yields a flipper instance
|
26
|
-
# use Flipper::Api::Middleware, lambda { Flipper.new(...) }
|
27
|
-
#
|
28
|
-
def initialize(app, flipper_or_block)
|
12
|
+
def initialize(app)
|
29
13
|
@app = app
|
30
14
|
|
31
|
-
if flipper_or_block.respond_to?(:call)
|
32
|
-
@flipper_block = flipper_or_block
|
33
|
-
else
|
34
|
-
@flipper = flipper_or_block
|
35
|
-
end
|
36
|
-
|
37
15
|
@action_collection = ActionCollection.new
|
38
16
|
@action_collection.add Api::V1::Actions::PercentageOfTimeGate
|
39
17
|
@action_collection.add Api::V1::Actions::PercentageOfActorsGate
|
40
18
|
@action_collection.add Api::V1::Actions::ActorsGate
|
41
19
|
@action_collection.add Api::V1::Actions::GroupsGate
|
42
20
|
@action_collection.add Api::V1::Actions::BooleanGate
|
21
|
+
@action_collection.add Api::V1::Actions::ClearFeature
|
43
22
|
@action_collection.add Api::V1::Actions::Feature
|
44
23
|
@action_collection.add Api::V1::Actions::Features
|
45
24
|
end
|
46
25
|
|
47
|
-
def flipper
|
48
|
-
@flipper ||= @flipper_block.call
|
49
|
-
end
|
50
|
-
|
51
26
|
def call(env)
|
52
27
|
dup.call!(env)
|
53
28
|
end
|
@@ -56,9 +31,9 @@ module Flipper
|
|
56
31
|
request = Rack::Request.new(env)
|
57
32
|
action_class = @action_collection.action_for_request(request)
|
58
33
|
if action_class.nil?
|
59
|
-
@app.status = 404
|
60
34
|
@app.call(env)
|
61
35
|
else
|
36
|
+
flipper = env.fetch('flipper')
|
62
37
|
action_class.run(flipper, request)
|
63
38
|
end
|
64
39
|
end
|
@@ -6,7 +6,7 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Actions
|
8
8
|
class ActorsGate < Api::Action
|
9
|
-
route %r{
|
9
|
+
route %r{features/[^/]*/actors/?\Z}
|
10
10
|
|
11
11
|
def post
|
12
12
|
ensure_valid_params
|
@@ -29,10 +29,6 @@ module Flipper
|
|
29
29
|
private
|
30
30
|
|
31
31
|
def ensure_valid_params
|
32
|
-
unless feature_names.include?(feature_name)
|
33
|
-
json_error_response(:feature_not_found)
|
34
|
-
end
|
35
|
-
|
36
32
|
json_error_response(:flipper_id_invalid) if flipper_id.nil?
|
37
33
|
end
|
38
34
|
|
@@ -43,10 +39,6 @@ module Flipper
|
|
43
39
|
def flipper_id
|
44
40
|
@flipper_id ||= params['flipper_id']
|
45
41
|
end
|
46
|
-
|
47
|
-
def feature_names
|
48
|
-
@feature_names ||= flipper.adapter.features
|
49
|
-
end
|
50
42
|
end
|
51
43
|
end
|
52
44
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'flipper/api/action'
|
2
|
+
require 'flipper/api/v1/decorators/feature'
|
3
|
+
|
4
|
+
module Flipper
|
5
|
+
module Api
|
6
|
+
module V1
|
7
|
+
module Actions
|
8
|
+
class ClearFeature < Api::Action
|
9
|
+
route %r{features/[^/]*/clear/?\Z}
|
10
|
+
|
11
|
+
def delete
|
12
|
+
feature_name = Rack::Utils.unescape(path_parts[-2])
|
13
|
+
feature = flipper[feature_name]
|
14
|
+
flipper.adapter.clear(feature)
|
15
|
+
json_response({}, 204)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -6,25 +6,17 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Actions
|
8
8
|
class Feature < Api::Action
|
9
|
-
|
10
|
-
route %r{api/v1/features/[^/]*/?\Z}
|
9
|
+
route %r{features/[^/]*/?\Z}
|
11
10
|
|
12
11
|
def get
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
else
|
17
|
-
json_error_response(:feature_not_found)
|
18
|
-
end
|
12
|
+
return json_error_response(:feature_not_found) unless feature_exists?(feature_name)
|
13
|
+
feature = Decorators::Feature.new(flipper[feature_name])
|
14
|
+
json_response(feature.as_json)
|
19
15
|
end
|
20
16
|
|
21
17
|
def delete
|
22
|
-
|
23
|
-
|
24
|
-
json_response({}, 204)
|
25
|
-
else
|
26
|
-
json_error_response(:feature_not_found)
|
27
|
-
end
|
18
|
+
flipper.remove(feature_name)
|
19
|
+
json_response({}, 204)
|
28
20
|
end
|
29
21
|
|
30
22
|
private
|
@@ -33,8 +25,8 @@ module Flipper
|
|
33
25
|
@feature_name ||= Rack::Utils.unescape(path_parts.last)
|
34
26
|
end
|
35
27
|
|
36
|
-
def
|
37
|
-
|
28
|
+
def feature_exists?(feature_name)
|
29
|
+
flipper.features.map(&:key).include?(feature_name)
|
38
30
|
end
|
39
31
|
end
|
40
32
|
end
|
@@ -1,23 +1,35 @@
|
|
1
1
|
require 'flipper/api/action'
|
2
2
|
require 'flipper/api/v1/decorators/feature'
|
3
|
-
require 'json'
|
4
3
|
|
5
4
|
module Flipper
|
6
5
|
module Api
|
7
6
|
module V1
|
8
7
|
module Actions
|
9
8
|
class Features < Api::Action
|
10
|
-
|
11
|
-
route %r{api/v1/features\Z}
|
9
|
+
route(/features\Z/)
|
12
10
|
|
13
11
|
def get
|
14
|
-
|
12
|
+
keys = params['keys']
|
13
|
+
features = if keys
|
14
|
+
names = keys.split(',')
|
15
|
+
if names.empty?
|
16
|
+
[]
|
17
|
+
else
|
18
|
+
existing_feature_names = names.keep_if do |feature_name|
|
19
|
+
feature_exists?(feature_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
flipper.preload(existing_feature_names)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
flipper.features
|
26
|
+
end
|
27
|
+
|
28
|
+
decorated_features = features.map do |feature|
|
15
29
|
Decorators::Feature.new(feature).as_json
|
16
|
-
|
30
|
+
end
|
17
31
|
|
18
|
-
json_response(
|
19
|
-
features: features
|
20
|
-
})
|
32
|
+
json_response(features: decorated_features)
|
21
33
|
end
|
22
34
|
|
23
35
|
def post
|
@@ -27,6 +39,12 @@ module Flipper
|
|
27
39
|
decorated_feature = Decorators::Feature.new(feature)
|
28
40
|
json_response(decorated_feature.as_json, 200)
|
29
41
|
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def feature_exists?(feature_name)
|
46
|
+
flipper.features.map(&:key).include?(feature_name)
|
47
|
+
end
|
30
48
|
end
|
31
49
|
end
|
32
50
|
end
|
@@ -6,7 +6,7 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Actions
|
8
8
|
class GroupsGate < Api::Action
|
9
|
-
route %r{
|
9
|
+
route %r{features/[^/]*/groups/?\Z}
|
10
10
|
|
11
11
|
def post
|
12
12
|
ensure_valid_params
|
@@ -27,8 +27,23 @@ module Flipper
|
|
27
27
|
private
|
28
28
|
|
29
29
|
def ensure_valid_params
|
30
|
-
|
31
|
-
|
30
|
+
if group_name.nil? || group_name.empty?
|
31
|
+
json_error_response(:name_invalid)
|
32
|
+
end
|
33
|
+
|
34
|
+
return if allow_unregistered_groups?
|
35
|
+
return if Flipper.group_exists?(group_name)
|
36
|
+
|
37
|
+
json_error_response(:group_not_registered)
|
38
|
+
end
|
39
|
+
|
40
|
+
def allow_unregistered_groups?
|
41
|
+
allow_unregistered_groups = params['allow_unregistered_groups']
|
42
|
+
allow_unregistered_groups && allow_unregistered_groups == 'true'
|
43
|
+
end
|
44
|
+
|
45
|
+
def disallow_unregistered_groups?
|
46
|
+
!allow_unregistered_groups?
|
32
47
|
end
|
33
48
|
|
34
49
|
def feature_name
|
@@ -38,10 +53,6 @@ module Flipper
|
|
38
53
|
def group_name
|
39
54
|
@group_name ||= params['name']
|
40
55
|
end
|
41
|
-
|
42
|
-
def feature_names
|
43
|
-
@feature_names ||= flipper.adapter.features
|
44
|
-
end
|
45
56
|
end
|
46
57
|
end
|
47
58
|
end
|
@@ -6,10 +6,13 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Actions
|
8
8
|
class PercentageOfActorsGate < Api::Action
|
9
|
-
route %r{
|
9
|
+
route %r{features/[^/]*/percentage_of_actors/?\Z}
|
10
10
|
|
11
11
|
def post
|
12
|
-
|
12
|
+
if percentage < 0 || percentage > 100
|
13
|
+
json_error_response(:percentage_invalid)
|
14
|
+
end
|
15
|
+
|
13
16
|
feature = flipper[feature_name]
|
14
17
|
feature.enable_percentage_of_actors(percentage)
|
15
18
|
decorated_feature = Decorators::Feature.new(feature)
|
@@ -17,7 +20,6 @@ module Flipper
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def delete
|
20
|
-
ensure_valid_disable_params
|
21
23
|
feature = flipper[feature_name]
|
22
24
|
feature.disable_percentage_of_actors
|
23
25
|
decorated_feature = Decorators::Feature.new(feature)
|
@@ -26,22 +28,6 @@ module Flipper
|
|
26
28
|
|
27
29
|
private
|
28
30
|
|
29
|
-
def ensure_valid_enable_params
|
30
|
-
unless feature_names.include?(feature_name)
|
31
|
-
json_error_response(:feature_not_found)
|
32
|
-
end
|
33
|
-
|
34
|
-
if percentage < 0 || percentage > 100
|
35
|
-
json_error_response(:percentage_invalid)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def ensure_valid_disable_params
|
40
|
-
unless feature_names.include?(feature_name)
|
41
|
-
json_error_response(:feature_not_found)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
31
|
def feature_name
|
46
32
|
@feature_name ||= Rack::Utils.unescape(path_parts[-2])
|
47
33
|
end
|
@@ -53,12 +39,8 @@ module Flipper
|
|
53
39
|
-1
|
54
40
|
end
|
55
41
|
end
|
56
|
-
|
57
|
-
def feature_names
|
58
|
-
@feature_names ||= flipper.adapter.features
|
59
|
-
end
|
60
|
-
end
|
61
42
|
end
|
62
43
|
end
|
63
44
|
end
|
64
45
|
end
|
46
|
+
end
|
@@ -6,10 +6,13 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Actions
|
8
8
|
class PercentageOfTimeGate < Api::Action
|
9
|
-
route %r{
|
9
|
+
route %r{features/[^/]*/percentage_of_time/?\Z}
|
10
10
|
|
11
11
|
def post
|
12
|
-
|
12
|
+
if percentage < 0 || percentage > 100
|
13
|
+
json_error_response(:percentage_invalid)
|
14
|
+
end
|
15
|
+
|
13
16
|
feature = flipper[feature_name]
|
14
17
|
feature.enable_percentage_of_time(percentage)
|
15
18
|
decorated_feature = Decorators::Feature.new(feature)
|
@@ -17,31 +20,15 @@ module Flipper
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def delete
|
20
|
-
ensure_valid_disable_params
|
21
23
|
feature = flipper[feature_name]
|
22
24
|
feature.disable_percentage_of_time
|
25
|
+
|
23
26
|
decorated_feature = Decorators::Feature.new(feature)
|
24
27
|
json_response(decorated_feature.as_json, 200)
|
25
28
|
end
|
26
29
|
|
27
30
|
private
|
28
31
|
|
29
|
-
def ensure_valid_enable_params
|
30
|
-
unless feature_names.include?(feature_name)
|
31
|
-
json_error_response(:feature_not_found)
|
32
|
-
end
|
33
|
-
|
34
|
-
if percentage < 0 || percentage > 100
|
35
|
-
json_error_response(:percentage_invalid)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def ensure_valid_disable_params
|
40
|
-
unless feature_names.include?(feature_name)
|
41
|
-
json_error_response(:feature_not_found)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
32
|
def feature_name
|
46
33
|
@feature_name ||= Rack::Utils.unescape(path_parts[-2])
|
47
34
|
end
|
@@ -53,10 +40,6 @@ module Flipper
|
|
53
40
|
-1
|
54
41
|
end
|
55
42
|
end
|
56
|
-
|
57
|
-
def feature_names
|
58
|
-
@feature_names ||= flipper.adapter.features
|
59
|
-
end
|
60
43
|
end
|
61
44
|
end
|
62
45
|
end
|
@@ -6,19 +6,18 @@ module Flipper
|
|
6
6
|
module V1
|
7
7
|
module Decorators
|
8
8
|
class Feature < SimpleDelegator
|
9
|
-
|
10
9
|
# Public: The feature being decorated.
|
11
10
|
alias_method :feature, :__getobj__
|
12
11
|
|
13
12
|
# Public: Returns instance as hash that is ready to be json dumped.
|
14
13
|
def as_json
|
15
|
-
gate_values = feature.
|
14
|
+
gate_values = feature.adapter.get(self)
|
16
15
|
{
|
17
16
|
'key' => key,
|
18
17
|
'state' => state.to_s,
|
19
|
-
'gates' => gates.map
|
18
|
+
'gates' => gates.map do |gate|
|
20
19
|
Decorators::Gate.new(gate, gate_values[gate.key]).as_json
|
21
|
-
|
20
|
+
end,
|
22
21
|
}
|
23
22
|
end
|
24
23
|
end
|
data/lib/flipper/api.rb
CHANGED
@@ -1,43 +1,27 @@
|
|
1
1
|
require 'rack'
|
2
2
|
require 'flipper'
|
3
|
+
require 'flipper/middleware/setup_env'
|
4
|
+
require 'flipper/middleware/memoizer'
|
3
5
|
require 'flipper/api/middleware'
|
6
|
+
require 'flipper/api/json_params'
|
4
7
|
require 'flipper/api/actor'
|
5
8
|
|
6
9
|
module Flipper
|
7
10
|
module Api
|
8
11
|
CONTENT_TYPE = 'application/json'.freeze
|
9
12
|
|
10
|
-
def self.app(flipper)
|
11
|
-
app =
|
13
|
+
def self.app(flipper = nil)
|
14
|
+
app = ->(_) { [404, { 'Content-Type'.freeze => CONTENT_TYPE }, ['{}'.freeze]] }
|
12
15
|
builder = Rack::Builder.new
|
13
16
|
yield builder if block_given?
|
14
|
-
builder.use Flipper::
|
17
|
+
builder.use Flipper::Middleware::SetupEnv, flipper
|
18
|
+
builder.use Flipper::Middleware::Memoizer
|
19
|
+
builder.use Flipper::Api::JsonParams
|
20
|
+
builder.use Flipper::Api::Middleware
|
15
21
|
builder.run app
|
22
|
+
klass = self
|
23
|
+
builder.define_singleton_method(:inspect) { klass.inspect } # pretty rake routes output
|
16
24
|
builder
|
17
25
|
end
|
18
|
-
|
19
|
-
class App
|
20
|
-
# Public: HTTP response code
|
21
|
-
# Use this method to update status code before responding
|
22
|
-
attr_writer :status
|
23
|
-
|
24
|
-
def initialize(status, headers, body)
|
25
|
-
@status = status
|
26
|
-
@headers = headers
|
27
|
-
@body = body
|
28
|
-
end
|
29
|
-
|
30
|
-
# Public : Rack expects object that responds to call
|
31
|
-
# env - environment hash
|
32
|
-
def call(env)
|
33
|
-
response
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def response
|
39
|
-
[@status, @headers, @body]
|
40
|
-
end
|
41
|
-
end
|
42
26
|
end
|
43
27
|
end
|
data/lib/flipper/version.rb
CHANGED