api_explorer 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
});
|