better_rest 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c7075c76283c5d80eaf7a1b277a64378a6564b08
4
- data.tar.gz: a2565755ea3043e17f2d703a910ce1cc132fc2a6
3
+ metadata.gz: e391c09a3930c6c9f2d5bdcc35aedf4296109aad
4
+ data.tar.gz: 944d0e611bc34c43717109678ec441b4e8ff2aab
5
5
  SHA512:
6
- metadata.gz: fa1d80f4cee1b2043d862f06e279ac13bbb95bc946292f5312cc9ba317230836d0d5feacd1eb9ad7e7cb21adebe7aced9434fcfd26b9c7751fe91bb430664e43
7
- data.tar.gz: c8e0e912bd2b05e9cc5c5ba86d6fb6b28042c25fa29923bbab877a7b8d01c4f0632e69a3c6c143f910ad2f1d5b2280a28dc6b6bb4b52f490d407f54ecd6d6c2e
6
+ metadata.gz: c38a7f7355728f3dec51213ac23dc4c29ad5cb8bdd478a9ccdf671a6eb5e715d15201f3fcb5466a4332471d2331877eb5ea48c9345441820d3fac6ac333e44e3
7
+ data.tar.gz: 2e51051265116b638ddd25bea50ad1fbb761b81d1555011e8146aa8e7cdbbb115c31d51780deac028d3b239df5336d221aa80b77534bae90bce687ca579ba29e
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ requests
3
+ logs
4
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'sinatra'
4
+ gem 'typhoeus'
5
+ gem 'vegas'
6
+ gem 'json'
7
+ gem 'rake'
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ ethon (0.7.1)
5
+ ffi (>= 1.3.0)
6
+ ffi (1.9.3)
7
+ json (1.8.1)
8
+ rack (1.5.2)
9
+ rack-protection (1.5.3)
10
+ rack
11
+ rake (10.3.2)
12
+ sinatra (1.4.5)
13
+ rack (~> 1.4)
14
+ rack-protection (~> 1.4)
15
+ tilt (~> 1.3, >= 1.3.4)
16
+ tilt (1.4.1)
17
+ typhoeus (0.6.9)
18
+ ethon (>= 0.7.1)
19
+ vegas (0.1.11)
20
+ rack (>= 1.0.0)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ json
27
+ rake
28
+ sinatra
29
+ typhoeus
30
+ vegas
data/README.md CHANGED
@@ -1,41 +1,34 @@
1
- # BetteR
1
+ # BetteR [![Build Status](https://travis-ci.org/at1as/BetteR.svg?branch=master)](https://travis-ci.org/at1as/BetteR) [![Gem Version](https://badge.fury.io/rb/better_rest.svg)](http://badge.fury.io/rb/better_rest)
2
2
 
3
- BetteR is a a REST testing client written in Ruby and served by Sinatra.
3
+ BetteR is a a REST test client written in Ruby and served by Sinatra.
4
4
 
5
5
  BetteR emphasises both a clean and easy to use interface, as well as allowing users to have a very granuler control over their requests (things like following redirects, verbosity of response and timeout intervals are all configurable). The current feature set is modest, but what it does, it aims to do well.
6
6
 
7
- ## Screenshot
7
+ ### Screenshot
8
8
 
9
- ![Screenshot](http://at1as.github.io/github_repo_assets/BetteR-reqeust.jpg)
9
+ ![Screenshot](http://at1as.github.io/github_repo_assets/better-rest-client.jpg)
10
10
 
11
- ## Usage
11
+ ### Usage
12
12
 
13
- The easiest way to use BetteR is to install it using the gem:
13
+ The easiest way to use BetteR is to install it using the [Ruby Gem](http://rubygems.org/gems/better_rest) (note that this usually lags a few commits behind):
14
14
  ```bash
15
15
  $ gem install better_rest
16
16
  ```
17
- Or download the repository here for the latest version and launch BetteR via:
17
+ Or download the repository here for the latest version and launch via:
18
18
  ```bash
19
19
  $ ./bin/better_rest
20
20
  ```
21
- ## Logs
21
+ To try BetteR, without installing the Gem, it's also hosted on [Heroku](http://better-rest.herokuapp.com/). Note that when run on Heroku, some of functionality won't work due to lack of access to the filesystem (saving logs, etc.). Also note that this is likely to be from an older commit.
22
22
 
23
- Logs (if enabled from the Settings menu in the UI) will be stored in the following location
24
- ```bash
25
- ./logs/YYYY-MM-DD.log
26
- ```
27
- ## Dependencies
23
+ ### Dependencies
28
24
 
29
- Requires a ruby installation with the following gems installed (installation via the gem will eventually take care of these dependencies, but currently does not):
30
- - sinatra
31
- - typhoeus
32
- - vegas
33
- - json
25
+ See Gemfile for dependencies
34
26
 
35
- ## TODO
27
+ ### TODO
36
28
 
37
- * Add OAuth/OAuth2 support
29
+ * POSTMAN import
30
+ * OAuth/OAuth2 support
38
31
  * Update current deprecated Basic/Digest Auth method
39
- * Add ability to save requests
40
- * Add download to file
41
- * Add support for more than one variable
32
+ * Download to file
33
+ * Support more than one variable
34
+ * Delete logs
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require './lib/better_rest.rb'
2
+ task :default => [:test]
3
+
4
+ task :test do
5
+ ruby "./bin/better_rest"
6
+ end
data/better_rest.gemspec CHANGED
@@ -1,13 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "better_rest"
3
- s.version = "0.1.1"
3
+ s.version = "0.2.0"
4
4
  s.licenses = ['MIT']
5
- s.summary = "REST test Client"
6
- s.date = "2014-08-29"
7
- s.description = "This is a REST API test client accessible via the browser."
5
+ s.summary = "REST Test Client"
6
+ s.date = "2014-12-13"
7
+ s.description = "A Configurable REST API test client accessible via your browser"
8
8
  s.authors = ["Jason Willems"]
9
9
  s.email = ["jason@willems.ca"]
10
10
  s.homepage = "https://github.com/at1as/BetteR"
11
- s.files = `git ls-files`.split("\n")
11
+ s.files = `git ls-files`.split("\n")
12
12
  s.executables << 'better_rest'
13
13
  end
data/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ require './lib/better_rest.rb'
2
+ run Sinatra::Application
data/lib/better_rest.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
2
6
 
3
7
  require 'sinatra'
4
8
  require 'typhoeus'
@@ -12,129 +16,223 @@ helpers do
12
16
  alias_method :h, :escape_html
13
17
  end
14
18
 
19
+ configure do
20
+ dirs = ['logs', 'requests', 'tmp']
21
+ dirs.each do |folder|
22
+ Dir.mkdir(folder) unless File.directory? folder
23
+ end
24
+ end
25
+
15
26
  BETTER_SIGNATURE = "BetteR - https://github.com/at1as/BetteR"
16
27
 
28
+
29
+ # Return default values
17
30
  get '/?' do
18
31
  @requests = ["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"]
19
32
  @times = ["1", "2", "5", "10"]
20
- @timeout = ["1","2","5","10","60"]
21
- @validHeaderCount = 1
22
- @headerHash = {"" => ""}
23
- @follow, @verbose, @ssl, @loggingOn = true, true, false, false
24
- @visible = ["displayed", "hidden", "displayed", "displayed", "displayed"] #Ordered display toggle for frontend: REQUEST, AUTH, HEADERS, PAYLOAD, RESULTS
25
- @payloadHeight = "100px"
33
+ @header_hash = {"" => ""}
34
+ @follow, @verbose, @ssl, @log_requests = true, true, false, false
35
+ @timeout_interval = 1
26
36
 
27
37
  erb :index
28
38
  end
29
39
 
30
- post '/' do
31
- # Set Defaults
32
- @headerHash = {}
33
- @validHeaderCount = 1
34
- @formResponse = true
35
- @follow, @verbose, @ssl, @loggingOn = true, true, false, false
36
- @requestBody = params[:payload]
37
- @visible = [:servURLDiv, :servAuthDiv, :servHeaderDiv, :servePayloadDiv, :servResultsDiv].map{ |k| params[k] }
38
- @var_key = params[:varKey]
39
- @var_value = params[:varValue]
40
- @ContentType = "text/plain"
41
- @payloadHeight = params[:payloadHeight] ||= "100px"
42
-
43
- puts "PH: #{@payloadHeight}"
44
-
45
- # Loop through Header key/value pairs
46
- # If a header is created and deleted in the UI before submit, headerCount will not renormalize (and will exceed the number headers sent)
47
- # This will check that a particular header exists, before adding it to the Hash
48
- params[:headerCount].to_i.times do |i|
49
- @keyIncrement = "key#{i}"
50
- @valueIncrement = "value#{i}"
51
-
52
- if !(params.fetch(@keyIncrement, '').empty? || params.fetch(@valueIncrement, '').empty?)
53
- @headerHash[params[@keyIncrement]] = params[@valueIncrement]
54
- @validHeaderCount += 1
55
- end
56
- end
57
40
 
58
- # Shameless branding. Only if User-Agent isn't user specified
59
- @headerHash["User-Agent"] ||= BETTER_SIGNATURE
41
+ # Send a request
42
+ before '/request' do
43
+ request.body.rewind
44
+ @request_body = JSON.parse request.body.read
45
+ end
46
+
47
+ post '/request' do
48
+ puts @request_body
60
49
 
61
- # Check which options the user set or default to the following
62
- @follow = false if params[:followlocation] == ""
63
- @verbose = false if params[:verbose] == ""
64
- @ssl = true if params[:ssl_verifypeer] == "on"
65
- @loggingOn = true if params[:enableLogging] == "on"
50
+ # Request Configuration
51
+ @follow = @request_body['redirect'] rescue false
52
+ @verbose = @request_body['verbose'] rescue false
53
+ @ssl = @request_body['ssl_ver'] rescue false
54
+ @log_requests = @request_body['logging'] rescue false
55
+ @timeout_interval = Integer(@request_body['timeout']) rescue 1
56
+ @request_body['headers']['User-Agent'] = BETTER_SIGNATURE unless @request_body['headers']['User-Agent']
66
57
 
67
- # For parallel Requests
58
+ # Create the Request
68
59
  hydra = Typhoeus::Hydra.new
69
-
70
- # Create the Request (swap variable keys for values, if they have been set)
71
60
  request = Typhoeus::Request.new(
72
- params[:url].gsub("{{#{@var_key}}}", @var_value),
73
- method: params[:requestType],
74
- username: params[:usr].gsub("{{#{@var_key}}}", @var_value),
75
- password: params[:pwd].gsub("{{#{@var_key}}}", @var_value),
76
- auth_method: :auto, #Should ideally not be auto, in order to test unideal APIs
77
- headers: @headerHash,
78
- body: params[:payload].gsub("{{#{@var_key}}}", @var_value),
61
+ @request_body["url"],
62
+ method: @request_body["request"],
63
+ username: @request_body["user"],
64
+ password: @request_body["password"],
65
+ auth_method: :auto,
66
+ headers: @request_body["headers"],
67
+ body: @request_body["payload"],
79
68
  followlocation: @follow,
80
69
  verbose: @verbose,
81
70
  ssl_verifypeer: @ssl,
82
- timeout: Integer(params[:timeoutInterval])
71
+ timeout: @timeout_interval
83
72
  )
84
73
 
85
- # Modify Request Payload to include datafile, if present
86
- if params[:datafile]
87
- @requestBody = { content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
88
- request.options[:body] = @requestBody #{ content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
74
+ # Modify request object if necessary
75
+ unless @request_body['file'].empty?
76
+ request.options[:body] = { file: File.open('tmp/' + @request_body['file'], 'r') }
89
77
  end
90
78
 
91
- # Substitute Header Values for defined variables
92
- request.options[:headers].each do |key, val|
93
- if val.to_s.include? "{{#{@var_key}}}"
94
- request.options[:headers][key.to_s] = val.gsub("{{#{@var_key}}}", @var_value)
95
- end
79
+ # Remove unused fields from request
80
+ request.options.delete(:body) if request.options[:body].empty?
81
+ if @request_body['user'].empty? || @request_body['password'].empty?
82
+ request.options.delete(:username)
83
+ request.options.delete(:password)
84
+ request.options.delete(:auth_method)
96
85
  end
97
86
 
98
- # Remove unused fields from request (some APIs don't handle unexpected fields)
99
- request.options.delete(:body) if request.options[:body] == ""
100
- request.options.delete(:username) if params[:usr] == ""
101
- request.options.delete(:password) if params[:pwd] == ""
102
- request.options.delete(:auth_method) if params[:pwd] == "" && params[:usr] == ""
103
-
104
87
  # Send the request (specified number of times)
105
- params[:times].to_i.times.map{ hydra.queue(request) }
88
+ @request_body['quantity'].to_i.times.map{ hydra.queue(request) }
106
89
  hydra.run
107
90
  response = request.response
108
91
 
109
- # If user-agent wasn't set by user, don't bother showing the user this default
110
- request.options[:headers].delete('User-Agent') && @headerHash.delete("User-Agent") if @headerHash["User-Agent"] == BETTER_SIGNATURE
111
-
112
- # Log the request response
113
- if @loggingOn
114
- File.open('log/' + Time.now.strftime("%Y-%m-%d") + '.log', 'a') do |file|
115
- file.write("-" * 10 + "\n" + Time.now.to_s + request.inspect + "\n\n" )
92
+ # Log the request
93
+ if @log_requests
94
+ File.open('logs/' + Time.now.strftime('%Y-%m-%d') + '.log', 'a') do |file|
95
+ file.write('-' * 10 + ?\n + Time.now.to_s + request.inspect + "\n\n")
116
96
  end
117
97
  end
118
98
 
119
- # These values will be used by the ERB page
120
- # Add the URL to the Request Options returned
99
+ # View response parameters
100
+ @response_body = {}
121
101
  request.options[:url] = request.url
122
- @requestOptions = JSON.pretty_generate(request.options)
123
- @returnBody = response.body
124
- @returnCode = response.return_code
125
- @returnTime = response.time
126
- @statCodeReturn = response.response_headers
127
- @requests = ["#{params[:requestType]}", "GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].uniq
128
- @times = ["#{params[:times]}", "1", "2", "5", "10"].uniq
129
- @timeout = ["1","2","5","10","60"]
102
+ @response_body['request_options'] = JSON.pretty_generate(request.options)
103
+ @response_body['return_msg'] = response.return_code.upcase
104
+ @response_body['return_code'] = response.code
105
+ @response_body['return_time'] = response.time
106
+ @response_body['return_body'] = response.body.force_encoding('UTF-8')
107
+ @response_body['return_headers'] = response.response_headers
108
+
109
+ @response_body.to_json
110
+ end
130
111
 
131
- erb :index
112
+
113
+ # Save Request
114
+ before '/save' do
115
+ request.body.rewind
116
+ @request_payload = JSON.parse request.body.read
132
117
  end
133
118
 
119
+ post '/save' do
120
+ name = @request_payload['name']
121
+ collection = @request_payload['collection']
122
+
123
+ if File.exists? "requests/#{collection}.json"
124
+ stored_collection = JSON.parse File.read("requests/#{collection}.json")
125
+ else
126
+ stored_collection = {}
127
+ end
128
+ stored_collection[name] = @request_payload
129
+
130
+ File.open("requests/#{collection}.json", "w") do |f|
131
+ f.write(stored_collection.to_json)
132
+ end
133
+ 200
134
+ end
135
+
136
+
137
+ # Load List of Requests
138
+ get '/savedrequests' do
139
+ collection_map = {}
140
+ collections = Dir["requests/*.json"]
141
+
142
+ collections.each do |collection|
143
+ collection_contents = JSON.parse File.read(collection)
144
+ collection_names = collection_contents.keys
145
+
146
+ # Strip extension and directory from filename
147
+ collection = collection[9..-6]
148
+ collection_map[collection] = collection_names.sort
149
+ end
150
+
151
+ if collections.length > 0
152
+ return collection_map.to_json
153
+ else
154
+ return 404
155
+ end
156
+ end
157
+
158
+
159
+ # Load Request
160
+ get '/savedrequests/:collection/:request' do
161
+ if File.exists? "requests/#{params[:collection]}.json"
162
+ collection = JSON.parse File.read("requests/#{params[:collection]}.json")
163
+ request = collection[params[:request]]
164
+ return request.to_json
165
+ else
166
+ return 404
167
+ end
168
+ 200
169
+ end
170
+
171
+
172
+ # Delete Request Collection
173
+ delete '/collections/:collection' do
174
+ if File.exists? "requests/#{params[:collection]}.json"
175
+ File.delete("requests/#{params[:collection]}.json")
176
+ else
177
+ return 404
178
+ end
179
+ 200
180
+ end
181
+
182
+
183
+ # Delete Request from Collection
184
+ delete '/collections/:collection/:request' do
185
+ if File.exists? "requests/#{params[:collection]}.json"
186
+ stored_collection = JSON.parse File.read("requests/#{params[:collection]}.json")
187
+ stored_collection.delete(params[:request])
188
+
189
+ File.open("requests/#{params[:collection]}.json", "w") do |f|
190
+ f.write(stored_collection.to_json)
191
+ end
192
+ else
193
+ return 404
194
+ end
195
+ 200
196
+ end
197
+
198
+
199
+ # Retrieve list of saved logs
200
+ get '/logs' do
201
+ entries = Dir["logs/*.log"]
202
+ entries = entries.map!{ |k| k[5..-5]}
203
+ return { :logs => entries }.to_json
204
+ end
205
+
206
+
207
+ # Download log
208
+ get '/logs/:log' do
209
+ begin
210
+ send_file "logs/#{params[:log]}.log"
211
+ rescue
212
+ return 404
213
+ end
214
+ end
215
+
216
+
217
+ # Upload file
218
+ # Clear directory writing file
219
+ post '/upload' do
220
+ FileUtils.rm_rf(Dir.glob('tmp/*'))
221
+ unless request.body.nil?
222
+ File.open('tmp/' + params[:file][:filename], 'w') do |f|
223
+ f.write(params[:file][:tempfile].read)
224
+ end
225
+ end
226
+ 200
227
+ end
228
+
229
+
230
+ # Defaults to main page
134
231
  not_found do
135
232
  redirect '/'
136
233
  end
137
234
 
235
+
138
236
  # Returns Ruby/Sinatra Environment details
139
237
  get '/env' do
140
238
  <<-ENDRESPONSE
@@ -144,8 +242,13 @@ get '/env' do
144
242
  ENDRESPONSE
145
243
  end
146
244
 
245
+
147
246
  # Kills process. Work around for Vegas Gem not catching SIGINT from Terminal
148
247
  get '/quit' do
149
- puts "\nExiting..."
248
+ redirect to('/'), 200
249
+ end
250
+
251
+ after '/quit' do
252
+ puts "\nExiting..."
150
253
  exit!
151
254
  end