api_explorer 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +54 -23
- data/app/assets/javascripts/api_explorer/api.js +218 -197
- data/app/assets/stylesheets/api_explorer/api.css +6 -6
- data/app/controllers/api_explorer/api_controller.rb +53 -13
- data/app/helpers/api_explorer/api_helper.rb +1 -0
- data/lib/api_explorer/version.rb +1 -1
- data/test/dummy/app/controllers/users_controller.rb +6 -0
- data/test/dummy/config/routes.rb +2 -0
- data/test/dummy/lib/file2.json +1 -1
- data/test/dummy/log/development.log +1882 -0
- data/test/dummy/tmp/cache/assets/BCA/FB0/sprockets%2Fe82897852042905e6a55f41605476313 +0 -0
- data/test/dummy/tmp/cache/assets/BF5/890/sprockets%2F684520e56b0024497f60b05747f55726 +0 -0
- data/test/dummy/tmp/cache/assets/C76/1D0/sprockets%2F14bb2119e8211782e884ac51420c844f +0 -0
- data/test/dummy/tmp/cache/assets/D34/1D0/sprockets%2Fa04676c94303a7caa9014ff0f40eed65 +0 -0
- data/test/dummy/tmp/cache/assets/D50/950/sprockets%2F4714ce629d693fd95c1fd16ff7773a1b +0 -0
- data/test/dummy/tmp/cache/assets/D7B/0A0/sprockets%2F012437e537bed2cf9787aaf79db6e81c +0 -0
- data/test/dummy/tmp/cache/assets/D8B/310/sprockets%2F8c1640fafd6202b711c3da935daead71 +0 -0
- data/test/dummy/tmp/cache/assets/D8E/620/sprockets%2Faf16b0cae770d1267bc54cb11af0979b +0 -0
- data/test/dummy/tmp/cache/assets/DDD/8B0/sprockets%2F2641be1d4b59fd5fd668e5ab696ede5b +0 -0
- data/test/dummy/tmp/cache/assets/ECB/620/sprockets%2Ff199edb8fca027ddc9cbdcf471cfd8fc +0 -0
- metadata +4 -2
data/README.md
CHANGED
@@ -14,33 +14,56 @@ API Explorer is a tool that reads a specification and creates a console where de
|
|
14
14
|
- Supports HTTP basic authentication and HMAC-SHA1 hash authentication.
|
15
15
|
|
16
16
|
## Precondition
|
17
|
-
Given that it makes a request to the same server, it requires a multi-threaded server. On this example we will use 'thin'
|
17
|
+
Given that it makes a request to the same server, it requires a multi-threaded server. On this example we will use 'thin' and 'unicorn'.
|
18
18
|
|
19
19
|
|
20
|
-
## Configure thin server on threaded mode
|
20
|
+
## Configure thin server on threaded mode
|
21
21
|
|
22
22
|
Add thin to the Gemfile.
|
23
23
|
```
|
24
24
|
gem 'thin', '~> 1.6.1'
|
25
25
|
```
|
26
26
|
|
27
|
+
Set thread safe mode in development.rb (or the right environment)
|
28
|
+
|
29
|
+
```
|
30
|
+
config.thread_safe!
|
31
|
+
```
|
32
|
+
|
27
33
|
Bundle install
|
28
34
|
```
|
29
35
|
bundle install
|
30
36
|
```
|
31
37
|
|
38
|
+
Test the server by running it with:
|
39
|
+
```
|
40
|
+
thin start --threaded
|
41
|
+
```
|
32
42
|
|
33
|
-
|
43
|
+
## Alternative - Configure unicorn server
|
34
44
|
|
45
|
+
Add unicorn to the Gemfile.
|
35
46
|
```
|
36
|
-
|
47
|
+
gem "unicorn", "~> 4.7.0"
|
48
|
+
```
|
49
|
+
|
50
|
+
Add the file 'unicorn.conf' to config/ with the following content:
|
51
|
+
|
52
|
+
```
|
53
|
+
worker_processes 3
|
54
|
+
```
|
55
|
+
|
56
|
+
Bundle install
|
57
|
+
```
|
58
|
+
bundle install
|
37
59
|
```
|
38
60
|
|
39
61
|
Test the server by running it with:
|
40
62
|
```
|
41
|
-
|
63
|
+
unicorn_rails -c config/unicorn.conf
|
42
64
|
```
|
43
65
|
|
66
|
+
|
44
67
|
## Install the gem
|
45
68
|
|
46
69
|
Add the gem to the Gemfile.
|
@@ -52,20 +75,23 @@ gem 'api_explorer'
|
|
52
75
|
Create a file named ws_specification.json (or any name you desire) and place it on /lib. An example can be:
|
53
76
|
|
54
77
|
```
|
55
|
-
{
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
78
|
+
{
|
79
|
+
"methods": [
|
80
|
+
{
|
81
|
+
"name": "Users index",
|
82
|
+
"url": "v1/users",
|
83
|
+
"description": "The index of users",
|
84
|
+
"method": "GET",
|
85
|
+
"parameters": [{"name": "API_TOKEN"}]
|
86
|
+
},
|
87
|
+
{
|
88
|
+
"name": "User login",
|
89
|
+
"url": "v1/users/login",
|
90
|
+
"description": "Users login",
|
91
|
+
"method": "POST",
|
92
|
+
"parameters": [{"name": "API_TOKEN"}, {"name": "email"}, {"name": "password"}]
|
93
|
+
}
|
94
|
+
]
|
69
95
|
}
|
70
96
|
```
|
71
97
|
|
@@ -73,7 +99,7 @@ Create an initializer in /config/initializers/api_explorer.rb with the following
|
|
73
99
|
|
74
100
|
```
|
75
101
|
ApiExplorer::use_file = true
|
76
|
-
ApiExplorer::json_path =
|
102
|
+
ApiExplorer::json_path = 'lib/ws_specification.json'
|
77
103
|
```
|
78
104
|
|
79
105
|
Another option can be:
|
@@ -98,16 +124,22 @@ That's it. Its ready to go.
|
|
98
124
|
|
99
125
|
## Run
|
100
126
|
|
101
|
-
Start thin
|
127
|
+
Start thin (or unicorn)
|
102
128
|
|
103
129
|
```
|
104
130
|
thin start --threaded
|
105
131
|
```
|
106
132
|
|
133
|
+
or
|
134
|
+
|
135
|
+
```
|
136
|
+
unicorn_rails -c config/unicorn.conf
|
137
|
+
```
|
138
|
+
|
107
139
|
And go to
|
108
140
|
|
109
141
|
```
|
110
|
-
http
|
142
|
+
http://<base_path>/api_explorer
|
111
143
|
```
|
112
144
|
|
113
145
|
## Contribute
|
@@ -119,7 +151,6 @@ http://localhost:3000/api_explorer
|
|
119
151
|
## Next improvements
|
120
152
|
|
121
153
|
- Better error handling
|
122
|
-
- Test with unicorn
|
123
154
|
- Test with Rails 4
|
124
155
|
- More authentication methods
|
125
156
|
- Support absolute URLs to test 3rd party APIs.
|
@@ -1,197 +1,218 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
1
|
+
|
2
|
+
$(function () {
|
3
|
+
|
4
|
+
// Match all containers and placeholders
|
5
|
+
var container = $("body.api_explorer"); // In order to avoid naming colisions, all the selectors are within this context
|
6
|
+
var parameters_container = $("#parameters_container", container);
|
7
|
+
var headers_container = $("#headers_container", container);
|
8
|
+
var authentication_container = $("#authentication_container", container);
|
9
|
+
var method_description = $("#method_description", container);
|
10
|
+
var select_method = $("#api_methods", container);
|
11
|
+
var response_placeholder = $("#response_placeholder", container);
|
12
|
+
var tab_history = $("#response_placeholder").find(".tab_history");
|
13
|
+
var history_menu = tab_history.find(".history_menu");
|
14
|
+
var authentication_method = $("#authentication_type", container);
|
15
|
+
|
16
|
+
// Change selected method
|
17
|
+
select_method.change(function(){
|
18
|
+
|
19
|
+
$("#graph_path", container).val($(this).val());
|
20
|
+
|
21
|
+
// Selected position
|
22
|
+
var position = $(this)[0].selectedIndex;
|
23
|
+
|
24
|
+
// if a method is selected
|
25
|
+
if (position > 0)
|
26
|
+
{
|
27
|
+
$.get("api_explorer/method", {position: position}).done(function(data){
|
28
|
+
parameters_container.html(data.parameters_html);
|
29
|
+
method_description.html(data.description);
|
30
|
+
|
31
|
+
parameters_container.show();
|
32
|
+
headers_container.show();
|
33
|
+
method_description.show();
|
34
|
+
authentication_container.show();
|
35
|
+
});
|
36
|
+
}
|
37
|
+
else
|
38
|
+
{
|
39
|
+
// Clean everything
|
40
|
+
parameters_container.html('');
|
41
|
+
method_description.html('');
|
42
|
+
parameters_container.hide();
|
43
|
+
headers_container.hide();
|
44
|
+
method_description.hide();
|
45
|
+
authentication_container.hide();
|
46
|
+
}
|
47
|
+
});
|
48
|
+
|
49
|
+
// Change authentication method
|
50
|
+
authentication_method.change(function(){
|
51
|
+
if ($(this).val() !== '')
|
52
|
+
{
|
53
|
+
$('.auth_wrapper', authentication_container).hide();
|
54
|
+
$('input[type="text"]',authentication_container).val('');
|
55
|
+
$('#' + $(this).val() ,authentication_container).show();
|
56
|
+
}
|
57
|
+
else{
|
58
|
+
// If 'none' is selected, hide authentication option containers
|
59
|
+
$('.auth_wrapper', authentication_container).hide();
|
60
|
+
$('input[type="text"]',authentication_container).val('');
|
61
|
+
}
|
62
|
+
});
|
63
|
+
|
64
|
+
// Clear parameters button
|
65
|
+
$(container).on('click', '#clear_parameters', function(){
|
66
|
+
$("input", parameters_container).val('');
|
67
|
+
});
|
68
|
+
|
69
|
+
// Clear the headers
|
70
|
+
$('#clear_headers', container).click(function(){
|
71
|
+
$("input", headers_container).val('');
|
72
|
+
$(".deletable", headers_container).remove();
|
73
|
+
|
74
|
+
});
|
75
|
+
|
76
|
+
// Clear authentication section
|
77
|
+
$('#clear_authentication', container).click(function(){
|
78
|
+
$("input", authentication_container).val('');
|
79
|
+
$("select", authentication_container).val('');
|
80
|
+
$(".auth_wrapper", authentication_container).hide();
|
81
|
+
});
|
82
|
+
|
83
|
+
// Add headers when focusing on headers input
|
84
|
+
headers_container.on('focus', ".parameter_input",function(){
|
85
|
+
header_line = $(this).parents(".headers_line");
|
86
|
+
if (header_line.is(':last-child'))
|
87
|
+
{
|
88
|
+
|
89
|
+
header_line.parent().append('<div class="headers_line"><div class="header_field"><input type="text" placeholder="Header name" name="header[name][]" class="parameter_input" /></div><div class="header_field"><input type="text" placeholder="Value" name="header[value][]" class="parameter_input" /></div></div>');
|
90
|
+
|
91
|
+
// Add delete button
|
92
|
+
header_line.append('<div class="delete_btn"></div>');
|
93
|
+
header_line.addClass('deletable');
|
94
|
+
}
|
95
|
+
});
|
96
|
+
|
97
|
+
// Delete header
|
98
|
+
headers_container.on('click', ".delete_btn",function(){
|
99
|
+
$(this).parents('.headers_line').remove();
|
100
|
+
});
|
101
|
+
|
102
|
+
// Funciton used to minimize sections
|
103
|
+
var minimize_container = function(self, min_container)
|
104
|
+
{
|
105
|
+
min_container.addClass('minimized');
|
106
|
+
self.removeClass('minimize');
|
107
|
+
self.addClass('maximize');
|
108
|
+
self.attr('title','Maximize');
|
109
|
+
};
|
110
|
+
|
111
|
+
// Function used to maximize sections
|
112
|
+
var maximize_container = function(self, max_container)
|
113
|
+
{
|
114
|
+
max_container.removeClass('minimized');
|
115
|
+
self.removeClass('maximize');
|
116
|
+
self.addClass('minimize');
|
117
|
+
self.attr('title','Minimize');
|
118
|
+
};
|
119
|
+
|
120
|
+
// Headers container minimize function
|
121
|
+
headers_container.on('click', ".minimize",function(){
|
122
|
+
minimize_container($(this), headers_container);
|
123
|
+
});
|
124
|
+
|
125
|
+
// Headers container maximize function
|
126
|
+
headers_container.on('click', ".maximize",function(){
|
127
|
+
maximize_container($(this),headers_container);
|
128
|
+
});
|
129
|
+
|
130
|
+
// Parameters container minimize function
|
131
|
+
parameters_container.on('click', ".minimize",function(){
|
132
|
+
minimize_container($(this),parameters_container);
|
133
|
+
});
|
134
|
+
|
135
|
+
// Parameters container maximize function
|
136
|
+
parameters_container.on('click', ".maximize",function(){
|
137
|
+
maximize_container($(this), parameters_container);
|
138
|
+
});
|
139
|
+
|
140
|
+
// Authentication container minimize function
|
141
|
+
authentication_container.on('click', ".minimize",function(){
|
142
|
+
minimize_container($(this),authentication_container);
|
143
|
+
});
|
144
|
+
|
145
|
+
// Authentication container maximize function
|
146
|
+
authentication_container.on('click', ".maximize",function(){
|
147
|
+
maximize_container($(this), authentication_container);
|
148
|
+
});
|
149
|
+
|
150
|
+
// History item selected
|
151
|
+
history_menu.on('click', '.history_item', function(){
|
152
|
+
$(".history_item", history_menu).removeClass('active');
|
153
|
+
$(this).addClass('active');
|
154
|
+
var history_content = tab_history.find(".history_content");
|
155
|
+
var timestamp = $(this).data('timestamp');
|
156
|
+
$(".content_wrapper", history_content).hide();
|
157
|
+
|
158
|
+
$("."+ timestamp, history_content).show();
|
159
|
+
});
|
160
|
+
|
161
|
+
// Make request
|
162
|
+
$("#api_explorer_submit", container).click(function(e) {
|
163
|
+
e.preventDefault();
|
164
|
+
|
165
|
+
// Build array of parameters
|
166
|
+
var data = $("input", parameters_container).serializeArray().concat($("input", headers_container).serializeArray()).concat($("input, select", authentication_container).serializeArray());
|
167
|
+
data.push({name: 'url', value: $("#graph_path", container).val()});
|
168
|
+
data.push({name: 'method', value: select_method.find('option:selected').data('method')});
|
169
|
+
|
170
|
+
// Send the information to the server
|
171
|
+
$.post("api_explorer/execute", data, function(response){
|
172
|
+
// Response returned, minimize headers, parameters and authentication
|
173
|
+
headers_container.addClass('minimized');
|
174
|
+
parameters_container.addClass('minimized');
|
175
|
+
authentication_container.addClass('minimized');
|
176
|
+
|
177
|
+
// Change minimize icon
|
178
|
+
headers_container.find('.minimize').removeClass('minimize').addClass('maximize');
|
179
|
+
parameters_container.find('.minimize').removeClass('minimize').addClass('maximize');
|
180
|
+
authentication_container.find('.minimize').removeClass('minimize').addClass('maximize');
|
181
|
+
|
182
|
+
// Set the html of the request/response
|
183
|
+
response_placeholder.find(".tab_response").find(".content").html(response.response_html);
|
184
|
+
response_placeholder.find(".tab_request").find(".content").html(response.request_html);
|
185
|
+
|
186
|
+
// Set History
|
187
|
+
var history_content = tab_history.find(".history_content");
|
188
|
+
$(".history_item", history_menu).removeClass('active');
|
189
|
+
|
190
|
+
// If I have more than 9 elements, remove the last one
|
191
|
+
if ($(".history_item", history_menu).length > 9)
|
192
|
+
{
|
193
|
+
$(".history_item", history_menu).last().remove();
|
194
|
+
$(".content_wrapper", history_content).last().remove();
|
195
|
+
}
|
196
|
+
history_content.prepend(response.history_html);
|
197
|
+
history_menu.prepend("<div class='history_item active' data-timestamp='"+ response.timestamp + "'>" + response.http_method + " to "+response.request_url +" ( at " + response.date +" ) " + "</div>");
|
198
|
+
|
199
|
+
// Select the current element in History
|
200
|
+
$(".content_wrapper", history_content).hide();
|
201
|
+
$("." + response.timestamp, history_content).show();
|
202
|
+
|
203
|
+
// Slide down the response placeholder and check the response tab as checked
|
204
|
+
response_placeholder.slideDown();
|
205
|
+
response_placeholder.find(".tab_response").find('input[type="radio"]').prop("checked", true);
|
206
|
+
|
207
|
+
// Scroll to response position
|
208
|
+
$('html, body').animate({
|
209
|
+
scrollTop: response_placeholder.offset().top + 50
|
210
|
+
}, 500);
|
211
|
+
|
212
|
+
|
213
|
+
}).error(function() {
|
214
|
+
alert('There was an error executing the webservice. Please check if you are using a multithreaded server');
|
215
|
+
});
|
216
|
+
|
217
|
+
});
|
218
|
+
});
|