railspp 0.3.5 → 0.3.6
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.
- checksums.yaml +4 -4
- data/lib/templates/api_documentation_initializer.txt +2 -2
- data/lib/templates/api_documentation_service.txt +173 -173
- data/lib/templates/documentation.index.erb.txt +111 -111
- data/lib/templates/documentation_controller.txt +45 -45
- data/lib/templates/exception_handler.txt +14 -14
- data/lib/templates/mini_test_controller.txt +19 -20
- data/lib/templates/rack_cors_initializer.txt +4 -4
- data/lib/templates/response.txt +29 -13
- data/lib/utils/strings.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7074cfa567f1b9340687317651b05e2a2a571562e0a7ce07d02120e89531b316
|
4
|
+
data.tar.gz: af31dd435546f415f7605449eeb622db3bd1a5eea79f5c1b2c03a79c405aa97d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71512d68c5337a92c0328f57069f5e509b22ecacb3fa83df0c0062fb341b1316446feef444756b9e9816d960f9df39302d8daead30801dfe1ea8185c91fbc877
|
7
|
+
data.tar.gz: 6a3e96ad180cf6b7b7fe9721a52788275d05b3f996d20f2408764da23850eb5bac710953803d564ecce395244a3e3ef0f176a857404cc9409b19847548fd4bf4
|
@@ -1,206 +1,206 @@
|
|
1
1
|
class APIDocumentationService
|
2
2
|
class << self
|
3
3
|
def generate_js_file
|
4
|
-
|
5
|
-
|
4
|
+
all_routes = get_api_routes
|
5
|
+
documentation_js_str = all_routes.map { |e| handle_js_for_route(e) }.join("\n")
|
6
6
|
|
7
|
-
|
7
|
+
File.open(output_path, "w+") { |f| f.write(documentation_js_str) }
|
8
8
|
end
|
9
9
|
|
10
10
|
def namespaces
|
11
|
-
|
12
|
-
|
11
|
+
# Whitelist namespaces
|
12
|
+
[:api]
|
13
13
|
end
|
14
14
|
|
15
15
|
def docs_namespaces
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
namespaces.each_with_object({}) do |item, acc|
|
17
|
+
acc[item] = true
|
18
|
+
acc
|
19
|
+
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def get_api_routes
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
get_all_routes.select do |e|
|
24
|
+
path_array = e[:route].split('/')
|
25
|
+
path_array.length > 1 && docs_namespaces[path_array[1].to_sym]
|
26
|
+
end
|
27
27
|
end
|
28
28
|
|
29
29
|
def camelize_route route
|
30
|
-
|
31
|
-
|
30
|
+
camel_route = route[:route].split('/').reject { |e| e == '' }.map { |e| /\:/.match(e) ? e.gsub!(':', '') + 'Param' : e }.map { |e| e.capitalize }.join('')
|
31
|
+
route[:method].downcase + camel_route
|
32
32
|
end
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
def output_path
|
37
|
+
__dir__ + '/../../app/assets/javascripts/documentation.js'
|
38
|
+
end
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
def get_all_routes
|
41
|
+
Rails.application.routes.routes.map { |e| { route: e.path.spec.to_s.split('(')[0], method: e.verb } }.map { |e| e[:route] && e[:method] ? e.merge(camel_cased: camelize_route(e)) : e }.select { |e| e[:route] }
|
42
|
+
end
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
var headerObject = {};
|
56
|
-
var tempHeaderKey = null;
|
57
|
-
for (var i = 0; i < headerList.length; i++) {
|
58
|
-
var eleHeader = headerList[i].value;
|
59
|
-
if (i % 2 !== 0 && tempHeaderKey) {
|
60
|
-
headerObject[tempHeaderKey] = eleHeader;
|
61
|
-
tempHeaderKey = null;
|
62
|
-
} else {
|
63
|
-
tempHeaderKey = eleHeader;
|
64
|
-
}
|
65
|
-
}
|
44
|
+
def handle_js_for_route route
|
45
|
+
camel_cased = route[:camel_cased]
|
46
|
+
javascript_string = ''
|
47
|
+
javascript_string += "window.#{camel_cased} = function() {
|
48
|
+
var allData = {
|
49
|
+
method: '#{route[:method]}',
|
50
|
+
route: '#{route[:route]}',
|
51
|
+
};
|
52
|
+
var paramList = document.getElementById('#{camel_cased}ParamsForm') && document.getElementById('#{camel_cased}ParamsForm').elements ? document.getElementById('#{camel_cased}ParamsForm').elements : [];
|
53
|
+
var headerList = document.getElementById('#{camel_cased}HeadersForm') && document.getElementById('#{camel_cased}HeadersForm').elements ? document.getElementById('#{camel_cased}HeadersForm').elements : [];
|
66
54
|
|
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
|
-
|
55
|
+
var headerObject = {};
|
56
|
+
var tempHeaderKey = null;
|
57
|
+
for (var i = 0; i < headerList.length; i++) {
|
58
|
+
var eleHeader = headerList[i].value;
|
59
|
+
if (i % 2 !== 0 && tempHeaderKey) {
|
60
|
+
headerObject[tempHeaderKey] = eleHeader;
|
61
|
+
tempHeaderKey = null;
|
62
|
+
} else {
|
63
|
+
tempHeaderKey = eleHeader;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
var hasHeaders = Object.keys(headerObject).length > 0;
|
68
|
+
var headers = { headers: headerObject };
|
69
|
+
|
70
|
+
var paramObject = {};
|
71
|
+
var tempParamKey = null;
|
72
|
+
for (var i = 0; i < paramList.length; i++) {
|
73
|
+
var eleParam = paramList[i].value;
|
74
|
+
if (i % 2 !== 0) {
|
75
|
+
paramObject[':' + tempParamKey] = eleParam;
|
76
|
+
tempParamKey = null;
|
77
|
+
} else {
|
78
|
+
tempParamKey = eleParam;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
var routeName = allData.route.split('/').map(function(e) { return paramObject[e] ? paramObject[e] : e; }).join('/');
|
83
|
+
|
84
|
+
if (allData.method !== 'GET') {
|
85
|
+
var bodyDataType = document.getElementById('#{camel_cased}DataType') && document.getElementById('#{camel_cased}DataType').value ? document.getElementById('#{camel_cased}DataType').value : false;
|
86
|
+
var formBoolean = bodyDataType === 'Form Data';
|
87
|
+
|
88
|
+
var bodyElements = [];
|
89
|
+
var bodyRawElements = document.getElementById('#{camel_cased}BodyForm') && document.getElementById('#{camel_cased}BodyForm').elements ? document.getElementById('#{camel_cased}BodyForm').elements : [];
|
90
|
+
for (var i = 0; i < bodyRawElements.length; i++) {
|
91
|
+
var eleParam = bodyRawElements[i].files ? bodyRawElements[i].files[0] : (bodyRawElements[i].value || null);
|
92
|
+
bodyElements.push(eleParam);
|
93
|
+
}
|
94
|
+
bodyElements = bodyElements.filter(function(e) {
|
95
|
+
return !!e;
|
96
|
+
});
|
97
|
+
|
98
|
+
var bodyObject = bodyDataType === 'Form Data' ? new FormData() : {};
|
99
|
+
var tempBodyKey = null;
|
100
|
+
bodyElements.forEach(function(e, i) {
|
101
|
+
if (i % 2 !== 0) {
|
102
|
+
if (formBoolean) {
|
103
|
+
bodyObject.append(tempBodyKey, e);
|
104
|
+
tempBodyKey = null;
|
105
|
+
} else {
|
106
|
+
bodyObject[tempBodyKey] = e;
|
107
|
+
tempBodyKey = null;
|
118
108
|
}
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
109
|
+
} else {
|
110
|
+
if (formBoolean) {
|
111
|
+
tempBodyKey = e;
|
112
|
+
} else {
|
113
|
+
bodyObject[e] = null;
|
114
|
+
tempBodyKey = e;
|
125
115
|
}
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
116
|
+
}
|
117
|
+
});
|
118
|
+
}
|
119
|
+
|
120
|
+
var qsElements = [];
|
121
|
+
var qsRawElements = document.getElementById('#{camel_cased}QSForm') && document.getElementById('#{camel_cased}QSForm').elements ? document.getElementById('#{camel_cased}QSForm').elements : [];
|
122
|
+
for (var i = 0; i < qsRawElements.length; i++) {
|
123
|
+
var eleParam = qsRawElements[i].value || null;
|
124
|
+
qsElements.push(eleParam);
|
125
|
+
}
|
126
|
+
|
127
|
+
qsElements = qsElements.filter(function(e) { return !!e; });
|
128
|
+
|
129
|
+
var qsObject = {};
|
130
|
+
var tempQSKey = null;
|
131
|
+
qsElements.forEach(function(e, i) {
|
132
|
+
if (i % 2 !== 0) {
|
133
|
+
qsObject[tempQSKey] = e;
|
134
|
+
tempQSKey = null;
|
135
|
+
} else {
|
136
|
+
qsObject[e] = null;
|
137
|
+
tempQSKey = e;
|
138
|
+
}
|
139
|
+
});
|
140
|
+
|
141
|
+
var qsLength = Object.keys(qsObject).length;
|
142
|
+
var querystring = qsLength > 0 ? '?' : '';
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
144
|
+
var qsCount = 0;
|
145
|
+
var qsArray = [];
|
146
|
+
if (querystring === '?') {
|
147
|
+
for (var qs in qsObject) {
|
148
|
+
if (qs && qsObject[qs]) {
|
149
|
+
qsArray.push(qs + '=' + qsObject[qs]);
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
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
|
-
|
154
|
+
querystring += qsArray.join('&');
|
155
|
+
|
156
|
+
var args = allData.method === 'GET' || allData.method === 'DELETE' ? [routeName + querystring, headers] : [routeName + querystring, bodyObject, headers];
|
157
|
+
if (!hasHeaders) args.pop();
|
158
|
+
var resultElement = document.getElementById('#{camel_cased}-results');
|
159
|
+
|
160
|
+
axios[allData.method.toLowerCase()](...args)
|
161
|
+
.then(function(resp) {
|
162
|
+
if (resp.status <= 300) {
|
163
|
+
resultElement.innerText = JSON.stringify(resp.data, null, 4);
|
164
|
+
} else {
|
165
|
+
resultElement.innerText = JSON.stringify(resp.data, null, 4);
|
166
|
+
}
|
167
|
+
})
|
168
|
+
.catch(function(err) {
|
169
|
+
var error_ajax = err && err.response && err.response.data ? err.response.data : err;
|
170
|
+
resultElement.innerText = JSON.stringify(error_ajax, null, 4);
|
171
|
+
});
|
172
|
+
};
|
173
|
+
"
|
174
|
+
|
175
|
+
javascript_string += "window.#{camel_cased}NewBody = function() {
|
176
|
+
var ele = document.getElementById('#{camel_cased}BodyForm');
|
177
|
+
ele.innerHTML += '<div class=\"d-flex f-row\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter key\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter value\"></div>';
|
178
|
+
};
|
179
|
+
|
180
|
+
"
|
181
|
+
|
182
|
+
javascript_string += "window.#{camel_cased}NewBodyFile = function() {
|
183
|
+
var ele = document.getElementById('#{camel_cased}BodyForm');
|
184
|
+
ele.innerHTML += '<div class=\"d-flex f-row\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter key\"><input class=\"w-100 m-1 form-control\" type=\"file\" multiple accept=\"*/*\" placeholder=\"Enter value\"></div>';
|
185
|
+
};
|
186
|
+
|
187
|
+
"
|
188
|
+
|
189
|
+
javascript_string += "window.#{camel_cased}NewQS = function() {
|
190
|
+
var ele = document.getElementById('#{camel_cased}QSForm');
|
191
|
+
ele.innerHTML += '<div class=\"d-flex f-row\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter key\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter value\"></div>';
|
192
|
+
};
|
193
|
+
"
|
194
194
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
195
|
+
javascript_string += "window.#{camel_cased}NewHeader = function() {
|
196
|
+
var ele = document.getElementById('#{camel_cased}HeadersForm');
|
197
|
+
ele.innerHTML += '<div class=\"d-flex f-row\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter key\"><input class=\"w-100 m-1 form-control\" type=\"text\" placeholder=\"Enter value\"></div>';
|
198
|
+
};
|
199
199
|
|
200
|
-
|
200
|
+
";
|
201
201
|
|
202
|
-
|
203
|
-
|
202
|
+
javascript_string
|
203
|
+
end
|
204
204
|
|
205
205
|
end
|
206
206
|
end
|
@@ -1,127 +1,127 @@
|
|
1
1
|
<div class="header p-3 bg-dark card-shadow d-flex flex-row justify-content-between">
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
</a>
|
6
|
-
<h1 class="h1 h-100 align-items-center text-white ml-3">API Documentation</h1>
|
7
|
-
</div>
|
8
|
-
<a class="d-flex align-items-center cursor-pointer">
|
9
|
-
<h2 class="h5 text-white" onclick="goBack()">Go Back</h2>
|
2
|
+
<div class="d-flex flex-row">
|
3
|
+
<a href='/' class="h-100">
|
4
|
+
<img class="d-flex flex-column align-items-center justify-content-center" src="https://s3-us-west-1.amazonaws.com/manoftech/ruby.png" alt="" height='50' width='50' />
|
10
5
|
</a>
|
6
|
+
<h1 class="h1 h-100 align-items-center text-white ml-3">API Documentation</h1>
|
7
|
+
</div>
|
8
|
+
<a class="d-flex align-items-center cursor-pointer">
|
9
|
+
<h2 class="h5 text-white" onclick="goBack()">Go Back</h2>
|
10
|
+
</a>
|
11
11
|
</div>
|
12
12
|
|
13
13
|
<div class="card-body p-3 w-100 p-1">
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
14
|
+
<% @all_routes.each do |data| %>
|
15
|
+
<div class="card card-outline-secondary w-100 flex-respond-row card-shadow">
|
16
|
+
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 p-1 card-shadow">
|
17
|
+
<div class='card-header <%= "#{data[:route_header]}" %>'>
|
18
|
+
<span class="mr-1"><%= data[:method] %>:</span>
|
19
|
+
<span><%= data[:route] %></span>
|
20
|
+
</div>
|
21
|
+
<div class="card-body p-2 w-100" style="max-height: 550px; overflow: auto;">
|
22
|
+
<% if data[:middleware] && data[:middleware].length > 0 %>
|
23
|
+
<h2 class="h5">Middleware Used:</h2>
|
24
|
+
<ul>
|
25
|
+
<% data[:middleware].each do |ware| %>
|
26
|
+
<li class="h6"><%= "#{ware}" %></li>
|
27
|
+
<% end %>
|
28
|
+
</ul>
|
29
|
+
<% end %>
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
<h2 class="h5">Description:
|
32
|
+
<ul>
|
33
|
+
<% data[:description].each do |ware| %>
|
34
|
+
<li class="h6"><%= "#{ware}" %></li>
|
35
|
+
<% end %>
|
36
|
+
</ul>
|
37
|
+
</h2>
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
39
|
+
<div class="d-flex f-row w-100">
|
40
|
+
<h2 class="w-100 h6">Headers:</h2>
|
41
|
+
<button class="<%= "#{data[:submit_button_color]} rounded-circle" %>" onclick="<%= "#{data[:submit_button_color]}NewHeader()" %>">+</button>
|
42
|
+
</div>
|
43
|
+
<div class="d-flex f-row w-100">
|
44
|
+
<form id="<%= data[:camel_cased] %>HeadersForm" class="w-100">
|
45
|
+
<div class="d-flex f-row">
|
46
|
+
<input type="text" class="w-100 m-1 d-flex f-row form-control" placeholder="Enter key">
|
47
|
+
<input type="text" class="w-100 m-1 form-control" placeholder="Enter value">
|
48
|
+
</div>
|
49
|
+
</form>
|
50
|
+
</div>
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
</div>
|
66
|
-
<% else %>
|
67
|
-
<span></span>
|
68
|
-
<% end %>
|
69
|
-
<% if data[:allow_body] %>
|
70
|
-
<div class="d-flex f-row w-100">
|
71
|
-
<h2 class="w-100 h6">Body:</h2>
|
72
|
-
<button class="<%= "#{data[:submit_button_color]} rounded mr-2" %>" onclick="<%= "#{data[:camel_cased]}NewBodyFile()" %>">Add File</button>
|
73
|
-
<button class="<%= "#{data[:submit_button_color]} rounded-circle" %>" onclick="<%= "#{data[:camel_cased]}NewBody()" %>">+</button>
|
74
|
-
</div>
|
75
|
-
<div class="d-flex f-row w-100">
|
76
|
-
<form id='<%= "#{data[:camel_cased]}BodyForm" %>'class='w-100'>
|
77
|
-
<div class='d-flex f-row'>
|
78
|
-
<input type='text' class='w-100 m-1 form-control' placeholder='Enter key'>
|
79
|
-
<input type='text' class='w-100 m-1 form-control' placeholder='Enter value'>
|
80
|
-
</div>
|
81
|
-
</form>
|
82
|
-
</div>
|
83
|
-
<% else %>
|
84
|
-
<span></span>
|
85
|
-
<% end %>
|
86
|
-
<div class="d-flex f-row w-100">
|
87
|
-
<h2 class="w-100 h6">Querystrings: </h2>
|
88
|
-
<button class="<%= "#{data[:submit_button_color]} rounded-circle" %>" onclick="<%= "#{data[:camel_cased]}NewQS()" %>">+</button>
|
89
|
-
</div>
|
90
|
-
<div class="d-flex f-row w-100">
|
91
|
-
<form id='<%= "#{data[:camel_cased]}QSForm" %>' class="w-100">
|
92
|
-
<div class="d-flex f-row">
|
93
|
-
<input type="text" class="w-100 m-1 form-control" placeholder="Enter key">
|
94
|
-
<input type="text" class="w-100 m-1 form-control" placeholder="Enter value">
|
95
|
-
</div>
|
96
|
-
</form>
|
97
|
-
</div>
|
98
|
-
<% if data[:allow_body] %>
|
99
|
-
<h2 class="h6">Body Data Type:</h2>
|
100
|
-
<select id="<%= "#{data[:camel_cased]}DataType" %>" class='form-control'>
|
101
|
-
<option value=''></option>
|
102
|
-
<option value='JSON'>JSON</option>
|
103
|
-
<option value='Form Data'>Form Data</option>
|
104
|
-
</select>
|
105
|
-
<% else %>
|
106
|
-
<span></span>
|
107
|
-
<% end %>
|
108
|
-
<div class="w-100 mt-2">
|
109
|
-
<button class="<%= "#{data[:submit_button_color]} w-100" %>" onclick="<%= "#{data[:camel_cased]}()" %>">Submit</button>
|
110
|
-
</div>
|
111
|
-
</div>
|
52
|
+
<% if data[:allow_params] %>
|
53
|
+
<div class="d-flex f-row w-100">
|
54
|
+
<h2 class="w-100 h6">Params:</h2>
|
55
|
+
</div>
|
56
|
+
<div class="d-flex f-row w-100">
|
57
|
+
<form id="<%= "#{data[:camel_cased]}ParamsForm" %>" class="w-100">
|
58
|
+
<%= data[:params].each do |param| %>
|
59
|
+
<div class="d-flex f-row">
|
60
|
+
<input id="<%= "#{data[:camel_cased]}-#{param}" %>" type="text" class="w-100 m-1 d-flex f-row form-control" value="<%= "#{param}" %>">
|
61
|
+
<input id="<%= "#{data[:camel_cased]}-#{param}-value" %>" type="text" class="w-100 m-1 form-control" placeholder="Enter value">
|
62
|
+
</div>
|
63
|
+
<% end %>
|
64
|
+
</form>
|
112
65
|
</div>
|
113
|
-
|
114
|
-
|
115
|
-
|
66
|
+
<% else %>
|
67
|
+
<span></span>
|
68
|
+
<% end %>
|
69
|
+
<% if data[:allow_body] %>
|
70
|
+
<div class="d-flex f-row w-100">
|
71
|
+
<h2 class="w-100 h6">Body:</h2>
|
72
|
+
<button class="<%= "#{data[:submit_button_color]} rounded mr-2" %>" onclick="<%= "#{data[:camel_cased]}NewBodyFile()" %>">Add File</button>
|
73
|
+
<button class="<%= "#{data[:submit_button_color]} rounded-circle" %>" onclick="<%= "#{data[:camel_cased]}NewBody()" %>">+</button>
|
74
|
+
</div>
|
75
|
+
<div class="d-flex f-row w-100">
|
76
|
+
<form id='<%= "#{data[:camel_cased]}BodyForm" %>'class='w-100'>
|
77
|
+
<div class='d-flex f-row'>
|
78
|
+
<input type='text' class='w-100 m-1 form-control' placeholder='Enter key'>
|
79
|
+
<input type='text' class='w-100 m-1 form-control' placeholder='Enter value'>
|
116
80
|
</div>
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
81
|
+
</form>
|
82
|
+
</div>
|
83
|
+
<% else %>
|
84
|
+
<span></span>
|
85
|
+
<% end %>
|
86
|
+
<div class="d-flex f-row w-100">
|
87
|
+
<h2 class="w-100 h6">Querystrings: </h2>
|
88
|
+
<button class="<%= "#{data[:submit_button_color]} rounded-circle" %>" onclick="<%= "#{data[:camel_cased]}NewQS()" %>">+</button>
|
89
|
+
</div>
|
90
|
+
<div class="d-flex f-row w-100">
|
91
|
+
<form id='<%= "#{data[:camel_cased]}QSForm" %>' class="w-100">
|
92
|
+
<div class="d-flex f-row">
|
93
|
+
<input type="text" class="w-100 m-1 form-control" placeholder="Enter key">
|
94
|
+
<input type="text" class="w-100 m-1 form-control" placeholder="Enter value">
|
121
95
|
</div>
|
96
|
+
</form>
|
122
97
|
</div>
|
98
|
+
<% if data[:allow_body] %>
|
99
|
+
<h2 class="h6">Body Data Type:</h2>
|
100
|
+
<select id="<%= "#{data[:camel_cased]}DataType" %>" class='form-control'>
|
101
|
+
<option value=''></option>
|
102
|
+
<option value='JSON'>JSON</option>
|
103
|
+
<option value='Form Data'>Form Data</option>
|
104
|
+
</select>
|
105
|
+
<% else %>
|
106
|
+
<span></span>
|
107
|
+
<% end %>
|
108
|
+
<div class="w-100 mt-2">
|
109
|
+
<button class="<%= "#{data[:submit_button_color]} w-100" %>" onclick="<%= "#{data[:camel_cased]}()" %>">Submit</button>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
</div>
|
113
|
+
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-6 col-xl-6 p-1 card-shadow p-1">
|
114
|
+
<div class="card-header">
|
115
|
+
<h2 class="h5">Sample Data</h2>
|
123
116
|
</div>
|
124
|
-
|
117
|
+
<div class='card-body' style="max-height: 550px; overflow: auto;">
|
118
|
+
<code style="overflow: auto; display: block;">
|
119
|
+
<span id="<%= "#{data[:camel_cased]}-results" %>" style="white-space: pre;"></span>
|
120
|
+
</code>
|
121
|
+
</div>
|
122
|
+
</div>
|
123
|
+
</div>
|
124
|
+
<% end %>
|
125
125
|
</div>
|
126
126
|
|
127
127
|
|
@@ -1,52 +1,52 @@
|
|
1
1
|
class DocumentationController < ApplicationController
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
def index
|
4
|
+
@all_routes = get_api_array
|
5
|
+
render template: 'documentation/index', layout: 'documentation'
|
6
|
+
end
|
7
7
|
|
8
8
|
private
|
9
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
|
-
|
10
|
+
def get_api_array
|
11
|
+
get_api_routes.map { |e| get_api_object(e) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_api_object route_hash
|
15
|
+
{
|
16
|
+
method: route_hash[:method],
|
17
|
+
route: route_hash[:route],
|
18
|
+
params: get_params(route_hash[:route]),
|
19
|
+
middleware: ['Not Available'],
|
20
|
+
route_header: "text-white bg-#{get_method_color(route_hash[:method])}",
|
21
|
+
submit_button_color: "btn btn-outline-#{get_method_color(route_hash[:method])}",
|
22
|
+
camel_cased: camelize_route(route_hash),
|
23
|
+
allow_params: route_hash[:route].split(':').length > 1,
|
24
|
+
allow_body: route_hash[:method] != 'GET',
|
25
|
+
description: ['No Description available'],
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_method_color method
|
30
|
+
lookup = {
|
31
|
+
GET: 'success',
|
32
|
+
POST: 'info',
|
33
|
+
PATCH: 'warning',
|
34
|
+
PUT: 'warning',
|
35
|
+
DELETE: 'danger',
|
36
|
+
}
|
37
|
+
lookup[method.to_sym] || 'dark'
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_params route
|
41
|
+
route.split('/').select { |e| /\:/.match(e) }.map { |e| e.split(':')[1] }
|
42
|
+
end
|
43
|
+
|
44
|
+
def camelize_route route
|
45
|
+
APIDocumentationService.camelize_route(route)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_api_routes
|
49
|
+
APIDocumentationService.get_api_routes
|
50
|
+
end
|
51
51
|
|
52
52
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module ExceptionHandler
|
2
|
-
|
2
|
+
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
8
|
-
rescue_from ActiveRecord::RecordInvalid do |e|
|
9
|
-
render_json({ error: e.message }, :unprocessable_entity)
|
10
|
-
end
|
11
|
-
rescue_from ActiveRecord::ActiveRecordError do |e|
|
12
|
-
render_json({ error: e.message }, :bad_request)
|
13
|
-
end
|
14
|
-
rescue_from ActionController::InvalidAuthenticityToken do |e|
|
15
|
-
render_json({ error: e.message }, :forbidden)
|
16
|
-
end
|
4
|
+
included do
|
5
|
+
rescue_from ActiveRecord::RecordNotFound do |e|
|
6
|
+
render_json({ error: e.message }, :not_found)
|
17
7
|
end
|
8
|
+
rescue_from ActiveRecord::RecordInvalid do |e|
|
9
|
+
render_json({ error: e.message }, :unprocessable_entity)
|
10
|
+
end
|
11
|
+
rescue_from ActiveRecord::ActiveRecordError do |e|
|
12
|
+
render_json({ error: e.message }, :bad_request)
|
13
|
+
end
|
14
|
+
rescue_from ActionController::InvalidAuthenticityToken do |e|
|
15
|
+
render_json({ error: e.message }, :forbidden)
|
16
|
+
end
|
17
|
+
end
|
18
18
|
|
19
19
|
end
|
@@ -12,33 +12,32 @@ class {{ NAMESPACE }}ControllerTest < ActionDispatch::IntegrationTest
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def data_types val
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
lookup = {
|
16
|
+
string: Faker::Lorem.sentence.to_s,
|
17
|
+
datetime: DateTime.now,
|
18
|
+
integer: 1,
|
19
|
+
boolean: false,
|
20
|
+
text: Faker::Lorem.paragraph.to_s,
|
21
|
+
}
|
22
|
+
lookup[val] || nil
|
23
23
|
end
|
24
24
|
|
25
25
|
def black_list_keys
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
{
|
27
|
+
id: true,
|
28
|
+
created_at: true,
|
29
|
+
updated_at: true,
|
30
|
+
}
|
31
31
|
end
|
32
32
|
|
33
33
|
def set_data_values
|
34
34
|
get_columns.each_with_object({}) do |e, acc|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
acc
|
35
|
+
key = e[:key]
|
36
|
+
val = e[:data_type]
|
37
|
+
if !black_list_keys[key]
|
38
|
+
acc[key] = data_types(val)
|
39
|
+
end
|
40
|
+
acc
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'rack/cors'
|
2
2
|
|
3
3
|
Rails.application.config.middleware.insert_before 0, Rack::Cors do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
allow do
|
5
|
+
origins '*'
|
6
|
+
resource '*', headers: :any, methods: [:get, :post, :patch, :put, :delete, :options]
|
7
|
+
end
|
8
8
|
end
|
data/lib/templates/response.txt
CHANGED
@@ -1,30 +1,46 @@
|
|
1
1
|
module Response
|
2
2
|
def render_json data, status
|
3
3
|
data = JSON.parse(data) if data.is_a?(String)
|
4
|
-
data[:data] = data[:data].map {|e|
|
5
|
-
data =
|
4
|
+
data[:data] = data[:data].map {|e| deleting(e) } if data && data[:data] && !data[:data].empty?
|
5
|
+
data = deleting(data) if data && !data[:data]
|
6
6
|
render json: data, status: status
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
def
|
11
|
+
def hide_keys
|
12
12
|
[
|
13
|
-
:password_digest
|
13
|
+
:password_digest,
|
14
14
|
]
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
def dictionary array
|
18
|
+
array.each_with_object({}) do |e, acc|
|
19
|
+
acc[e] = true
|
20
|
+
acc
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def prepare_json collection
|
25
|
+
JSON.parse(collection.to_json).symbolize_keys
|
26
|
+
end
|
27
|
+
|
28
|
+
def object_delete(json, lookup)
|
29
|
+
json.each do |k, e|
|
30
|
+
if e.is_a?(Hash)
|
31
|
+
json[k] = object_delete(e, lookup)
|
32
|
+
elsif e.is_a?(Array)
|
33
|
+
json[k] = json[k].map {|i| object_delete(i, lookup) }
|
34
|
+
elsif lookup[k]
|
35
|
+
json.delete(k)
|
26
36
|
end
|
27
37
|
end
|
28
38
|
json
|
29
39
|
end
|
40
|
+
|
41
|
+
def deleting(hash)
|
42
|
+
json = prepare_json(hash)
|
43
|
+
lookup = dictionary(hide_keys)
|
44
|
+
object_delete(json, lookup)
|
45
|
+
end
|
30
46
|
end
|
data/lib/utils/strings.rb
CHANGED