apic 0.0.1
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +45 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/apic/apic.js.coffee +5 -0
- data/app/assets/javascripts/apic/application.js +15 -0
- data/app/assets/javascripts/apic/components/console.js.coffee +125 -0
- data/app/assets/javascripts/apic/components/endpoints.js.coffee +53 -0
- data/app/assets/javascripts/apic/components/http-headers.js.coffee +97 -0
- data/app/assets/stylesheets/apic/application.css.scss +22 -0
- data/app/assets/stylesheets/apic/components/console.css.scss +8 -0
- data/app/assets/stylesheets/apic/components/endpoints.css.scss +9 -0
- data/app/assets/stylesheets/apic/components/http-headers.css.scss +46 -0
- data/app/controllers/apic/application_controller.rb +4 -0
- data/app/controllers/apic/controller.rb +13 -0
- data/app/helpers/apic/application_helper.rb +4 -0
- data/app/views/apic/application/_navigation.html.slim +9 -0
- data/app/views/apic/application/components/_console.html.slim +4 -0
- data/app/views/apic/application/components/_endpoints.html.slim +14 -0
- data/app/views/apic/application/components/_http_headers.html.slim +63 -0
- data/app/views/apic/application/index.html.slim +10 -0
- data/app/views/layouts/apic/application.html.erb +14 -0
- data/config/routes.rb +3 -0
- data/lib/apic.rb +54 -0
- data/lib/apic/engine.rb +11 -0
- data/lib/apic/extension.rb +13 -0
- data/lib/apic/params_cache.rb +19 -0
- data/lib/apic/version.rb +3 -0
- data/lib/tasks/apic_tasks.rake +4 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f34a4f4aab7e80104a44cadc30f087c953b02f26
|
4
|
+
data.tar.gz: f3f170ca3ddf9ce1d90bdc222a9f31786dbf91e6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43bf31780842c732681233c1e55a9b2abbcb20a25d6182b80b5c6fa30f082d0143df9a3442f2dced1eb01596b2495f3bde042662cf5dfab4e2a088571e939891
|
7
|
+
data.tar.gz: 0779a4e019559f14b99e10a0bfc7d463ff4ae2e42380438c6aa3dcdf5e4f6e51fd33163a1defa4ab8b589b738d120cd7897d91e103098d446f10cdcfa6b4928c
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
= Apic
|
2
|
+
|
3
|
+
[](https://travis-ci.org/hsbt/whispered) [](https://coveralls.io/r/randym/apic) [](https://gemnasium.com/randym/apic) [](https://codeclimate.com/github/randym/apic)
|
4
|
+
|
5
|
+
|
6
|
+
What you need to do?
|
7
|
+
|
8
|
+
add the gem to your Gemfile
|
9
|
+
|
10
|
+
```
|
11
|
+
gem 'apic'
|
12
|
+
```
|
13
|
+
|
14
|
+
require the gem in your application.rb
|
15
|
+
|
16
|
+
```
|
17
|
+
require 'apic'
|
18
|
+
```
|
19
|
+
|
20
|
+
mount the gem in your routes.rb
|
21
|
+
|
22
|
+
```
|
23
|
+
mount Apic::Engine => "/apic"
|
24
|
+
```
|
25
|
+
|
26
|
+
## and some groovy stuff too
|
27
|
+
|
28
|
+
Filter routes on a regex match
|
29
|
+
|
30
|
+
|
31
|
+
```
|
32
|
+
Apic.routes_matcher = /\/api\//
|
33
|
+
```
|
34
|
+
|
35
|
+
Tell us what your authorization filter is!
|
36
|
+
|
37
|
+
```
|
38
|
+
Apic.authorization_filter = :authenticate
|
39
|
+
```
|
40
|
+
|
41
|
+
|
42
|
+
git remote add origin https://github.com/randym/apic.git
|
43
|
+
|
44
|
+
|
45
|
+
This project rocks and uses MIT-LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
8
|
+
load 'rails/tasks/engine.rake'
|
9
|
+
|
10
|
+
Bundler::GemHelper.install_tasks
|
11
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// compiled file.
|
9
|
+
//
|
10
|
+
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
|
+
// about supported directives.
|
12
|
+
//= require jquery
|
13
|
+
//= require_tree .
|
14
|
+
//
|
15
|
+
//= require bootstrap-modal
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
# All this logic will automatically be available in application.js.
|
3
|
+
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
|
4
|
+
$.fn.extend
|
5
|
+
apic_console: (options) ->
|
6
|
+
settings =
|
7
|
+
endpoint: '.endpoints-component',
|
8
|
+
headers: '.http-headers',
|
9
|
+
params: '.parameter',
|
10
|
+
console: '.console',
|
11
|
+
console_log: '.console-log',
|
12
|
+
host: 'localhost:3000',
|
13
|
+
request_timeout: 10000,
|
14
|
+
timeout_callback: null,
|
15
|
+
response_callback: null
|
16
|
+
|
17
|
+
self = this
|
18
|
+
|
19
|
+
settings = $.extend settings, options
|
20
|
+
|
21
|
+
log_timeline = (method, uri) ->
|
22
|
+
self._end = new Date().getTime()
|
23
|
+
if console.log
|
24
|
+
console.log 'Finished: (time: ' + duration() + '):' + method + ' ' + uri
|
25
|
+
|
26
|
+
log_request = (xhr) ->
|
27
|
+
self._start = new Date().getTime()
|
28
|
+
console.log xhr
|
29
|
+
log_message "Request URL", uri()
|
30
|
+
log_message "Request Method", endpoint().verb
|
31
|
+
log_message "Response Code", [xhr.status, xhr.statusText].join(' ')
|
32
|
+
log_message "Request Headers", xhr.getAllResponseHeaders()
|
33
|
+
|
34
|
+
log_message = (title, message) ->
|
35
|
+
$(settings.console_log).append('<div><span class="log-header">' + title + '</span>:<span class="log-data"> ' + message + '</span></div>')
|
36
|
+
|
37
|
+
duration = ->
|
38
|
+
seconds = 0
|
39
|
+
time = _end - _start
|
40
|
+
try
|
41
|
+
seconds = ((time/10) / 60).toFixed(2)
|
42
|
+
catch e
|
43
|
+
0
|
44
|
+
seconds
|
45
|
+
|
46
|
+
endpoint = ->
|
47
|
+
$(settings.endpoint).data('endpoint')
|
48
|
+
|
49
|
+
headers = ->
|
50
|
+
$(settings.headers).data('items')
|
51
|
+
|
52
|
+
uri = ->
|
53
|
+
path = endpoint().path
|
54
|
+
for part in endpoint().parts
|
55
|
+
path = path.replace(':' + part, value_for part)
|
56
|
+
if endpoint().verb is 'GET'
|
57
|
+
path += query_string()
|
58
|
+
path
|
59
|
+
|
60
|
+
$('#do-me').on('click', -> send.apply self)
|
61
|
+
|
62
|
+
value_for = (name) ->
|
63
|
+
$(settings.params + ' [name="' + name + '"]').val()
|
64
|
+
|
65
|
+
parameters = ->
|
66
|
+
endpoint().template
|
67
|
+
|
68
|
+
body = ->
|
69
|
+
hash = {}
|
70
|
+
for param in parameters()
|
71
|
+
hash[param] = value_for param
|
72
|
+
hash
|
73
|
+
|
74
|
+
query_string = ->
|
75
|
+
args = []
|
76
|
+
for own key, value of body()
|
77
|
+
args.push key + '=' + encodeURIComponent(value)
|
78
|
+
args.join '&'
|
79
|
+
|
80
|
+
onload = (xhr) ->
|
81
|
+
if xhr.status is 200
|
82
|
+
try
|
83
|
+
json = JSON.parse(xhr.responseText)
|
84
|
+
text = JSON.stringify(json, undefined, 2)
|
85
|
+
catch e
|
86
|
+
text = xhr.responseText
|
87
|
+
$(settings.console).text(text)
|
88
|
+
else
|
89
|
+
$(settings.console).text(xhr.responseText)
|
90
|
+
|
91
|
+
log_request xhr
|
92
|
+
|
93
|
+
onerror = (response) ->
|
94
|
+
console.log response
|
95
|
+
|
96
|
+
request = () ->
|
97
|
+
xhr = new XMLHttpRequest
|
98
|
+
xhr.open endpoint().verb, uri()
|
99
|
+
set_headers xhr
|
100
|
+
xhr.onerror = (xhr) ->
|
101
|
+
onerror.apply self, [xhr]
|
102
|
+
xhr.onload = (response) ->
|
103
|
+
onload.apply self, [xhr]
|
104
|
+
xhr
|
105
|
+
|
106
|
+
set_headers = (xhr) ->
|
107
|
+
$.each headers(), (key, value) ->
|
108
|
+
xhr.setRequestHeader(key, value)
|
109
|
+
|
110
|
+
validate_params = () ->
|
111
|
+
missing =[]
|
112
|
+
for part in endpoint().parts
|
113
|
+
if value_for(part) is ""
|
114
|
+
missing.push(part)
|
115
|
+
if missing.length > 0
|
116
|
+
alert('url parts reqired: ' + missing)
|
117
|
+
missing.length is 0
|
118
|
+
|
119
|
+
send = () ->
|
120
|
+
if validate_params()
|
121
|
+
xhr = request()
|
122
|
+
if endpoint().verb is 'GET'
|
123
|
+
xhr.send()
|
124
|
+
else
|
125
|
+
xhr.send JSON.stringify(body)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
$.fn.extend
|
2
|
+
endpoints: (options) ->
|
3
|
+
settings =
|
4
|
+
select: '#selectEndpoint',
|
5
|
+
template: '.template',
|
6
|
+
parameter: '.parameter'
|
7
|
+
|
8
|
+
self = this
|
9
|
+
|
10
|
+
settings = $.extend settings, options
|
11
|
+
|
12
|
+
endpoints = $(self).data('endpoints')
|
13
|
+
|
14
|
+
$.each endpoints, (key, value) ->
|
15
|
+
option = $('<option>'+ key + '</option>')
|
16
|
+
console.log value
|
17
|
+
option.text('[restricted] ' + option.text()) if value.authorization_required
|
18
|
+
$(settings.select).append(option)
|
19
|
+
|
20
|
+
change = ->
|
21
|
+
endpoint = selected()
|
22
|
+
$(self).data('endpoint', endpoint)
|
23
|
+
populate_params endpoint
|
24
|
+
|
25
|
+
populate_params = (endpoint) ->
|
26
|
+
$(self).find(settings.parameter).remove()
|
27
|
+
$.each endpoint.parts, (index, name) ->
|
28
|
+
field_set_for name, {required: true}
|
29
|
+
$.each endpoint.template, (index, name) ->
|
30
|
+
el = field_set_for name
|
31
|
+
if ['DELETE', 'PATCH'].indexOf endpoint.verb >= 0
|
32
|
+
el.find('#input-_method').val(endpoint.verb.toLowerCase())
|
33
|
+
|
34
|
+
selected = ->
|
35
|
+
endpoints[$(settings.select).val()]
|
36
|
+
|
37
|
+
field_set_for = (name, options={}) ->
|
38
|
+
clone = $(self).find(settings.template).clone()
|
39
|
+
label = clone.find('label')
|
40
|
+
label.attr('for', "input-" + name)
|
41
|
+
label.text(name)
|
42
|
+
clone.find('input').attr('id', "input-"+name)
|
43
|
+
clone.find('input').attr('name', name)
|
44
|
+
clone.addClass(settings.parameter.slice(1))
|
45
|
+
clone.removeClass(settings.template.slice(1))
|
46
|
+
if options.required
|
47
|
+
clone.find('input').prop('required',true)
|
48
|
+
$(self).find('form').append(clone)
|
49
|
+
|
50
|
+
$(settings.select).on 'change', -> change.apply self
|
51
|
+
change.apply self
|
52
|
+
|
53
|
+
this
|
@@ -0,0 +1,97 @@
|
|
1
|
+
$.fn.extend
|
2
|
+
httpHeaders: (options) ->
|
3
|
+
settings =
|
4
|
+
presets: {}
|
5
|
+
|
6
|
+
$.each $(this).data(), (key, value) ->
|
7
|
+
settings[key] = value
|
8
|
+
|
9
|
+
settings = $.extend settings, options
|
10
|
+
|
11
|
+
$(this).data('items', settings.presets)
|
12
|
+
|
13
|
+
self = this
|
14
|
+
|
15
|
+
selected = undefined
|
16
|
+
|
17
|
+
add = ->
|
18
|
+
name = $('#selectHttpHeaderFieldName').val()
|
19
|
+
value = $('#inputHttpHeaderValue').val()
|
20
|
+
if !!name and !!value
|
21
|
+
tmp_items = items()
|
22
|
+
tmp_items[name] = value
|
23
|
+
$(self).data('items', tmp_items)
|
24
|
+
populate()
|
25
|
+
$('#httpHeadersModal').modal('hide')
|
26
|
+
|
27
|
+
remove = ->
|
28
|
+
if self.selected
|
29
|
+
headers = items()
|
30
|
+
delete headers[self.selected.data('key')]
|
31
|
+
$(self).data('items', headers)
|
32
|
+
self.selected.remove()
|
33
|
+
self.selected = undefined
|
34
|
+
populate()
|
35
|
+
|
36
|
+
edit = ->
|
37
|
+
name = self.selected.data('key')
|
38
|
+
headers = items()
|
39
|
+
value = headers[name]
|
40
|
+
$('#selectHttpHeaderFieldName').val(name)
|
41
|
+
$('#inputHttpHeaderValue').val(value)
|
42
|
+
$('#httpHeadersModal').modal('show')
|
43
|
+
|
44
|
+
create = ->
|
45
|
+
$('#selectHttpHeaderFieldName').prop("selectedIndex",0)
|
46
|
+
$('#inputHttpHeaderValue').val('')
|
47
|
+
$('#httpHeadersModal').modal('show')
|
48
|
+
|
49
|
+
show = ->
|
50
|
+
el = $('.headers')
|
51
|
+
el.toggle()
|
52
|
+
|
53
|
+
li = $(event.target).closest('li')
|
54
|
+
if $(el).is(":visible")
|
55
|
+
li.addClass('active')
|
56
|
+
else
|
57
|
+
li.removeClass('active')
|
58
|
+
|
59
|
+
list = ->
|
60
|
+
$(self).find('ul')
|
61
|
+
|
62
|
+
items = ->
|
63
|
+
$(self).data('items')
|
64
|
+
|
65
|
+
|
66
|
+
populate = ->
|
67
|
+
list().empty()
|
68
|
+
$.each items(), (key, value) ->
|
69
|
+
list().append(list_item(key, value))
|
70
|
+
select list().find('li:first')
|
71
|
+
|
72
|
+
|
73
|
+
select = (el) ->
|
74
|
+
$.each $('.http-headers-list li'), (index, el) ->
|
75
|
+
$(el).removeClass('active')
|
76
|
+
|
77
|
+
$(el).addClass('active')
|
78
|
+
self.selected = $(el)
|
79
|
+
|
80
|
+
list_item = (key, value)->
|
81
|
+
'<li class="http-header-item" data-key="' + key + '">' +
|
82
|
+
'<a href="#"><span class="header-key">' + key + ':</span>' +
|
83
|
+
'<span class="header-value">' + value + '</span></a></li>'
|
84
|
+
|
85
|
+
populate()
|
86
|
+
|
87
|
+
$('#httpHeadersModal a.add-http-header').on('click', -> add.apply self)
|
88
|
+
$('.create-http-header').on('click', -> create.apply self)
|
89
|
+
|
90
|
+
$('.remove-http-header').on('click', -> remove.apply self)
|
91
|
+
$('.http-headers-list').on('click', 'li', -> select this)
|
92
|
+
$('.http-headers-list').on('dblclick', 'li', -> edit.apply self)
|
93
|
+
$('.edit-headers').on('click', -> show.apply self)
|
94
|
+
|
95
|
+
this
|
96
|
+
|
97
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
14
|
+
@import "bootstrap";
|
15
|
+
body {
|
16
|
+
padding-top: 40px;
|
17
|
+
}
|
18
|
+
.navbar {
|
19
|
+
.brand {
|
20
|
+
margin-left: 5px;
|
21
|
+
}
|
22
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
.headers {
|
2
|
+
border-bottom: 1px solid #DDD;
|
3
|
+
padding: 5px;
|
4
|
+
display: none;
|
5
|
+
}
|
6
|
+
#httpHeadersModal {
|
7
|
+
width: 800px;
|
8
|
+
}
|
9
|
+
.http-headers-component {
|
10
|
+
margin-left: 10px;
|
11
|
+
min-height: 130px;
|
12
|
+
overflow-y: scroll;
|
13
|
+
h4 {
|
14
|
+
text-align: center;
|
15
|
+
}
|
16
|
+
.http-headers {
|
17
|
+
ul {
|
18
|
+
border: 1px solid #eee;
|
19
|
+
min-height: 100px;
|
20
|
+
margin-bottom: 5px;
|
21
|
+
}
|
22
|
+
.header-key {
|
23
|
+
display: inline-block;
|
24
|
+
height: 100%;
|
25
|
+
width: 180px;
|
26
|
+
text-align: right;
|
27
|
+
padding-right: 10px;
|
28
|
+
overflow: hidden;
|
29
|
+
}
|
30
|
+
a {
|
31
|
+
span {
|
32
|
+
display: inline-block;
|
33
|
+
overflow: hidden;
|
34
|
+
}
|
35
|
+
}
|
36
|
+
a:hover {
|
37
|
+
background-color: #0088cc;
|
38
|
+
color: #FFF
|
39
|
+
}
|
40
|
+
}
|
41
|
+
.http-headers-controls {
|
42
|
+
margin-bottom: 5px;
|
43
|
+
margin-left: 5px;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
div.endpoints-component( data-endpoints="#{@endpoints.to_json}")
|
2
|
+
h4 Endpoints
|
3
|
+
div.endpoints
|
4
|
+
form.form-horizontal
|
5
|
+
div.control-group
|
6
|
+
label.control-label(for="selectEndpoint") Api Endpoint
|
7
|
+
div.controls
|
8
|
+
select(id='selectEndpoint')
|
9
|
+
|
10
|
+
div.control-group.template
|
11
|
+
label.control-label(for="inputParam") Param Name
|
12
|
+
div.controls
|
13
|
+
input.input-xxlarge(id="inputParam" type="text")
|
14
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
div.row.headers
|
2
|
+
div.http-headers-component
|
3
|
+
h4 HTTP Headers
|
4
|
+
div.http-headers
|
5
|
+
ul.http-headers-list.nav.nav-list
|
6
|
+
|
7
|
+
div.http-headers-controls
|
8
|
+
a.btn.create-http-header(href='#httpHeadersModal')
|
9
|
+
== "+"
|
10
|
+
a(href='#' class='btn remove-http-header')
|
11
|
+
== "-"
|
12
|
+
|
13
|
+
div.modal.hide.fade(id='httpHeadersModal')
|
14
|
+
div.modal-header
|
15
|
+
button.close(type='button' data-dismiss='modal' aria-hidden='true')
|
16
|
+
== "×"
|
17
|
+
h4 Http Headers
|
18
|
+
div.modal-body
|
19
|
+
form.form-horizontal
|
20
|
+
div.control-group
|
21
|
+
label.control-label(for='selectHttpHeaderFieldName') Header
|
22
|
+
div.controls
|
23
|
+
select(id='selectHttpHeaderFieldName')
|
24
|
+
option Accept
|
25
|
+
option Accept-Charset
|
26
|
+
option Accept-Datetime
|
27
|
+
option Accept-Encoding
|
28
|
+
option Accept-Language
|
29
|
+
option Authorization
|
30
|
+
option Cache-Control
|
31
|
+
option Connection
|
32
|
+
option Content-Length
|
33
|
+
option Content-MD5
|
34
|
+
option Content-Type
|
35
|
+
option Cookie
|
36
|
+
option Date
|
37
|
+
option Expect
|
38
|
+
option From
|
39
|
+
option Host
|
40
|
+
option If-Match
|
41
|
+
option If-Modified-Since
|
42
|
+
option If-None-Match
|
43
|
+
option If-Range
|
44
|
+
option If-Unmodified-Since
|
45
|
+
option Max-Forwards
|
46
|
+
option Origin
|
47
|
+
option Pragma
|
48
|
+
option Proxy-Authorization
|
49
|
+
option Range
|
50
|
+
option Referer
|
51
|
+
option TE
|
52
|
+
option Upgrade
|
53
|
+
option User-Agent
|
54
|
+
option Via
|
55
|
+
option Warning
|
56
|
+
div.control-group
|
57
|
+
label.control-label(for='inputHttpHeaderValue') Value
|
58
|
+
div.controls
|
59
|
+
input.input-xxlarge(type='text' id='inputHttpHeaderValue' placeholder='value')
|
60
|
+
|
61
|
+
div.modal-footer
|
62
|
+
a.btn(href='#' data-dismiss='modal') Cancel
|
63
|
+
a.btn.btn-primary.add-http-header(href='#') Ok
|
@@ -0,0 +1,10 @@
|
|
1
|
+
div.container
|
2
|
+
== render :partial => "navigation"
|
3
|
+
== render :partial => "apic/application/components/http_headers"
|
4
|
+
div.row.endpoints
|
5
|
+
== render :partial => "apic/application/components/endpoints"
|
6
|
+
div.row
|
7
|
+
div.btn-toolbar
|
8
|
+
button#do-me.btn.btn-primary(href='#') Send
|
9
|
+
div.row
|
10
|
+
== render :partial => "apic/application/components/console"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Apic</title>
|
5
|
+
<%= stylesheet_link_tag "apic/application", media: "all" %>
|
6
|
+
<%= javascript_include_tag "apic/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
data/config/routes.rb
ADDED
data/lib/apic.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'apic/params_cache'
|
2
|
+
require "apic/extension"
|
3
|
+
require "apic/engine"
|
4
|
+
|
5
|
+
module Apic
|
6
|
+
|
7
|
+
mattr_accessor :authorization_filter
|
8
|
+
@@authorization_filter = nil
|
9
|
+
|
10
|
+
mattr_accessor :route_matcher
|
11
|
+
@@route_matcher = /\/api\//
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
def self.endpoints
|
16
|
+
@endpoints ||= Rails.application.routes.routes.reduce({}) do |hash, route|
|
17
|
+
if route.path.spec.to_s =~ @@route_matcher
|
18
|
+
route_spec = {
|
19
|
+
path: route.path.spec.to_s.gsub("(.:format)",".json"),
|
20
|
+
parts: route.parts - [:format],
|
21
|
+
verb: route.verb.source.gsub(/[\^\$]/,''),
|
22
|
+
template: template_for(route.defaults[:controller], route.defaults[:action])
|
23
|
+
}
|
24
|
+
if %(PATCH DELETE).include? route_spec[:verb]
|
25
|
+
route_spec[:template] = route_spec[:template] + ['_method']
|
26
|
+
end
|
27
|
+
if requires_authorization route.defaults[:controller], route.defaults[:action]
|
28
|
+
route_spec[:authorization_required] = true
|
29
|
+
end
|
30
|
+
|
31
|
+
hash[[route_spec[:verb],route_spec[:path]].join(' ')] = route_spec
|
32
|
+
end
|
33
|
+
hash
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.requires_authorization(controller, action_name)
|
38
|
+
return false unless @@authorization_filter
|
39
|
+
controller = (controller + '_controller').camelize.constantize
|
40
|
+
controller._process_action_callbacks.any? do |callback|
|
41
|
+
p @@authorization_filter
|
42
|
+
eval <<-RUBY_EVAL
|
43
|
+
#{callback.filter == @@authorization_filter} && #{callback.instance_values['compiled_options']}
|
44
|
+
RUBY_EVAL
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.template_for(controller, action)
|
49
|
+
(controller + '_controller').camelize.constantize
|
50
|
+
Apic::ParamsCache.params_for(controller, action) || []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
data/lib/apic/engine.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Apic
|
2
|
+
class ParamsCache
|
3
|
+
class << self
|
4
|
+
def add_action_params(cclass, actions)
|
5
|
+
action_params[cclass.name.underscore.gsub('_controller', '')] = actions
|
6
|
+
end
|
7
|
+
|
8
|
+
def action_params
|
9
|
+
@action_params ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def params_for(controller, action)
|
13
|
+
if controller = action_params[controller]
|
14
|
+
controller[action.to_sym]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/apic/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: apic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Randy Morgan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: slim-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sass-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bootstrap-sass
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.2.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.3.2.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: coffee-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: jquery-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Apic is a mountable rails engine that enables a web based console for
|
98
|
+
testing api endpoints.
|
99
|
+
email:
|
100
|
+
- digital.ipseity@gmail.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- app/assets/javascripts/apic/apic.js.coffee
|
106
|
+
- app/assets/javascripts/apic/application.js
|
107
|
+
- app/assets/javascripts/apic/components/console.js.coffee
|
108
|
+
- app/assets/javascripts/apic/components/endpoints.js.coffee
|
109
|
+
- app/assets/javascripts/apic/components/http-headers.js.coffee
|
110
|
+
- app/assets/stylesheets/apic/application.css.scss
|
111
|
+
- app/assets/stylesheets/apic/components/console.css.scss
|
112
|
+
- app/assets/stylesheets/apic/components/endpoints.css.scss
|
113
|
+
- app/assets/stylesheets/apic/components/http-headers.css.scss
|
114
|
+
- app/controllers/apic/application_controller.rb
|
115
|
+
- app/controllers/apic/controller.rb
|
116
|
+
- app/helpers/apic/application_helper.rb
|
117
|
+
- app/views/apic/application/_navigation.html.slim
|
118
|
+
- app/views/apic/application/components/_console.html.slim
|
119
|
+
- app/views/apic/application/components/_endpoints.html.slim
|
120
|
+
- app/views/apic/application/components/_http_headers.html.slim
|
121
|
+
- app/views/apic/application/index.html.slim
|
122
|
+
- app/views/layouts/apic/application.html.erb
|
123
|
+
- config/routes.rb
|
124
|
+
- lib/apic/engine.rb
|
125
|
+
- lib/apic/extension.rb
|
126
|
+
- lib/apic/params_cache.rb
|
127
|
+
- lib/apic/version.rb
|
128
|
+
- lib/apic.rb
|
129
|
+
- lib/tasks/apic_tasks.rake
|
130
|
+
- MIT-LICENSE
|
131
|
+
- Rakefile
|
132
|
+
- README.md
|
133
|
+
homepage: https://github.com/randym/apic/
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.0.2
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: Apic is a mountable rails engine that enables a web based console for testing
|
157
|
+
api endpoints.
|
158
|
+
test_files: []
|
159
|
+
has_rdoc:
|