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 +4 -4
- data/.gitignore +4 -0
- data/.travis.yml +5 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +30 -0
- data/README.md +16 -23
- data/Rakefile +6 -0
- data/better_rest.gemspec +5 -5
- data/config.ru +2 -0
- data/lib/better_rest.rb +189 -86
- data/public/bootstrap.min.css +5 -0
- data/public/main.css +390 -0
- data/views/index.erb +1002 -455
- metadata +12 -6
- data/better_rest-0.0.11.gem +0 -0
- data/public/mainCSS.css +0 -194
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e391c09a3930c6c9f2d5bdcc35aedf4296109aad
|
4
|
+
data.tar.gz: 944d0e611bc34c43717109678ec441b4e8ff2aab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c38a7f7355728f3dec51213ac23dc4c29ad5cb8bdd478a9ccdf671a6eb5e715d15201f3fcb5466a4332471d2331877eb5ea48c9345441820d3fac6ac333e44e3
|
7
|
+
data.tar.gz: 2e51051265116b638ddd25bea50ad1fbb761b81d1555011e8146aa8e7cdbbb115c31d51780deac028d3b239df5336d221aa80b77534bae90bce687ca579ba29e
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
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
|
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
|
-
|
7
|
+
### Screenshot
|
8
8
|
|
9
|
-
![Screenshot](http://at1as.github.io/github_repo_assets/
|
9
|
+
![Screenshot](http://at1as.github.io/github_repo_assets/better-rest-client.jpg)
|
10
10
|
|
11
|
-
|
11
|
+
### Usage
|
12
12
|
|
13
|
-
The easiest way to use BetteR is to install it using the
|
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
|
17
|
+
Or download the repository here for the latest version and launch via:
|
18
18
|
```bash
|
19
19
|
$ ./bin/better_rest
|
20
20
|
```
|
21
|
-
|
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
|
-
|
24
|
-
```bash
|
25
|
-
./logs/YYYY-MM-DD.log
|
26
|
-
```
|
27
|
-
## Dependencies
|
23
|
+
### Dependencies
|
28
24
|
|
29
|
-
|
30
|
-
- sinatra
|
31
|
-
- typhoeus
|
32
|
-
- vegas
|
33
|
-
- json
|
25
|
+
See Gemfile for dependencies
|
34
26
|
|
35
|
-
|
27
|
+
### TODO
|
36
28
|
|
37
|
-
*
|
29
|
+
* POSTMAN import
|
30
|
+
* OAuth/OAuth2 support
|
38
31
|
* Update current deprecated Basic/Digest Auth method
|
39
|
-
*
|
40
|
-
*
|
41
|
-
*
|
32
|
+
* Download to file
|
33
|
+
* Support more than one variable
|
34
|
+
* Delete logs
|
data/Rakefile
ADDED
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.
|
3
|
+
s.version = "0.2.0"
|
4
4
|
s.licenses = ['MIT']
|
5
|
-
s.summary = "REST
|
6
|
-
s.date = "2014-
|
7
|
-
s.description = "
|
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
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
|
-
@
|
21
|
-
@
|
22
|
-
@
|
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
|
-
|
59
|
-
|
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
|
-
#
|
62
|
-
@follow =
|
63
|
-
@verbose =
|
64
|
-
@ssl =
|
65
|
-
@
|
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
|
-
#
|
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
|
-
|
73
|
-
method:
|
74
|
-
username:
|
75
|
-
password:
|
76
|
-
auth_method: :auto,
|
77
|
-
headers: @
|
78
|
-
body:
|
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:
|
71
|
+
timeout: @timeout_interval
|
83
72
|
)
|
84
73
|
|
85
|
-
# Modify
|
86
|
-
|
87
|
-
|
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
|
-
#
|
92
|
-
request.options[:
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
88
|
+
@request_body['quantity'].to_i.times.map{ hydra.queue(request) }
|
106
89
|
hydra.run
|
107
90
|
response = request.response
|
108
91
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
#
|
120
|
-
|
99
|
+
# View response parameters
|
100
|
+
@response_body = {}
|
121
101
|
request.options[:url] = request.url
|
122
|
-
@
|
123
|
-
@
|
124
|
-
@
|
125
|
-
@
|
126
|
-
@
|
127
|
-
@
|
128
|
-
|
129
|
-
@
|
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
|
-
|
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
|
-
|
248
|
+
redirect to('/'), 200
|
249
|
+
end
|
250
|
+
|
251
|
+
after '/quit' do
|
252
|
+
puts "\nExiting..."
|
150
253
|
exit!
|
151
254
|
end
|