Skip to content

Commit

Permalink
Show and index endpoints can be used as JSON api
Browse files Browse the repository at this point in the history
  • Loading branch information
zcotter committed Oct 22, 2020
1 parent 9db10ad commit 60985a3
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 5 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ Rails.application.routes.draw do
end
```

## API Endpoints

The index and show routes can also respond with JSON data instead of HTML when the request's `Accept` header is
`application/json`

The index route also accepts query parameters to filter by user or group:
`/admin/rollout?user=someone`
`/admin/rollout?group=developers`

## Logging

To get the most out of **rollout-ui**, we recommend you to turn on logging
Expand Down
24 changes: 24 additions & 0 deletions lib/rollout/ui/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,29 @@ def format_change_value(value)
value
end
end

def json_request?
request.env['HTTP_ACCEPT'] == 'application/json'
end

# Filters features by user and group if those params are provided
def filtered_features(rollout, feature_names)
feature_names.select do |feature_name|
feature = rollout.get(feature_name)
user_match = params[:user].nil? || feature.users.member?(params[:user])
group_match = params[:group].nil? || feature.groups.member?(params[:group].to_sym)
user_match && group_match
end
end

# Returns a hash of feature data to be rendered as json
def feature_to_hash(feature)
{
data: feature.data,
groups: feature.groups,
name: feature.name,
percentage: feature.percentage
}
end
end
end
2 changes: 1 addition & 1 deletion lib/rollout/ui/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class Rollout
module UI
VERSION = "0.2.0"
VERSION = "0.3.0"
end
end
18 changes: 15 additions & 3 deletions lib/rollout/ui/web.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "sinatra"
require "sinatra/json"
require "rollout"

require "rollout/ui/version"
Expand All @@ -15,8 +16,15 @@ class Web < Sinatra::Base
get '/' do
@rollout = config.get(:instance)
@features = @rollout.features.sort_by(&:downcase)

slim :'features/index'
if json_request?
json(
filtered_features(@rollout, @features).map do |feature|
feature_to_hash(@rollout.get(feature))
end
)
else
slim :'features/index'
end
end

get '/features/new' do
Expand All @@ -31,7 +39,11 @@ class Web < Sinatra::Base
@rollout = config.get(:instance)
@feature = @rollout.get(params[:feature_name])

slim :'features/show'
if json_request?
json(feature_to_hash(@feature))
else
slim :'features/show'
end
end

post '/features/:feature_name' do
Expand Down
5 changes: 4 additions & 1 deletion rollout-ui.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ Gem::Specification.new do |spec|

spec.add_dependency 'rollout', '~> 2.5'
spec.add_dependency 'sinatra', '~> 2.0'
spec.add_dependency 'sinatra-contrib', '~> 2.1'
spec.add_dependency 'slim', '~> 4.0'

spec.add_development_dependency 'bundler', '~> 1.17'
spec.add_development_dependency 'bundler', '>= 1.17'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rerun', '~> 0.13'
spec.add_development_dependency 'rack-test'
spec.add_development_dependency 'pry'
end
93 changes: 93 additions & 0 deletions spec/rollout/ui/web_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
require 'spec_helper'
ENV['APP_ENV'] = 'test'
RSpec.describe 'Web UIp' do
include Rack::Test::Methods

def app
Rollout::UI::Web
end

it "renders index html" do
get '/'
expect(last_response.body.include?('Rollout UI'))
expect(last_response.status == 200)
end

it "renders index json" do
ROLLOUT.activate(:fake_test_feature_for_rollout_ui_webspec)
header 'Accept', 'application/json'
get '/'
expect(last_response.status == 200)
expect(last_response.headers['Content-Type'] == 'application/json')
response = JSON.parse(last_response.body)
expected_response = {
"data"=>{},
"groups"=>[],
"name"=>"fake_test_feature_for_rollout_ui_webspec",
"percentage"=>100.0
}
expect(response).to(include(expected_response))
ROLLOUT.delete(:fake_test_feature_for_rollout_ui_webspec)
end

it "renders index json filtered by user and group" do
ROLLOUT.deactivate(:fake_test_feature_for_rollout_ui_webspec)
ROLLOUT.activate_user(:fake_test_feature_for_rollout_ui_webspec, 'fake_user')
ROLLOUT.activate_group(:fake_test_feature_for_rollout_ui_webspec, :fake_group)

header 'Accept', 'application/json'
get '/?user=different_user'
expect(last_response.status == 200)
expect(last_response.headers['Content-Type'] == 'application/json')
response = JSON.parse(last_response.body)
expect(response == [])

expected_feature = {
"data" => {},
"groups" => ["fake_group"],
"name" => "fake_test_feature_for_rollout_ui_webspec",
"percentage" => 0.0
}
header 'Accept', 'application/json'
get '/?user=fake_user'
expect(last_response.status == 200)
expect(last_response.headers['Content-Type'] == 'application/json')
response = JSON.parse(last_response.body)
expect(response).to(include(expected_feature))

header 'Accept', 'application/json'
get '/?group=fake_group'
expect(last_response.status == 200)
expect(last_response.headers['Content-Type'] == 'application/json')
response = JSON.parse(last_response.body)
expect(response).to(include(expected_feature))

ROLLOUT.deactivate_user(:fake_test_feature_for_rollout_ui_webspec, 'fake_user')
ROLLOUT.deactivate_group(:fake_test_feature_for_rollout_ui_webspec, :fake_group)
ROLLOUT.delete(:fake_test_feature_for_rollout_ui_webspec)
end

it "renders show html" do
get '/features/test'
expect(last_response.body.include?('Rollout UI'))
expect(last_response.body.include?('test'))
expect(last_response.status == 200)
end

it "renders show json" do
ROLLOUT.activate(:fake_test_feature_for_rollout_ui_webspec)
header 'Accept', 'application/json'
get '/features/fake_test_feature_for_rollout_ui_webspec'
expect(last_response.status == 200)
expect(last_response.headers['Content-Type'] == 'application/json')
response = JSON.parse(last_response.body)
expected_response = {
"data"=>{},
"groups"=>[],
"name"=>"fake_test_feature_for_rollout_ui_webspec",
"percentage"=>100.0
}
expect(expected_response == response)
ROLLOUT.delete(:fake_test_feature_for_rollout_ui_webspec)
end
end
8 changes: 8 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
require "bundler/setup"
require "rollout/ui"
require 'rack/test'
require 'pry'
require 'redis'

REDIS = Redis.new
ROLLOUT = Rollout.new(REDIS)
Rollout::UI.configure do
instance { ROLLOUT }
end
RSpec.configure do |config|
# Enable flags like --only-failures and --next-failure
config.example_status_persistence_file_path = ".rspec_status"
Expand Down

0 comments on commit 60985a3

Please sign in to comment.