apic 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/hsbt/whispered.png)](https://travis-ci.org/hsbt/whispered) [![Coverage Status](https://coveralls.io/repos/randym/apic/badge.png?branch=master)](https://coveralls.io/r/randym/apic) [![Dependency Status](https://gemnasium.com/randym/apic.png)](https://gemnasium.com/randym/apic) [![Code Climate](https://codeclimate.com/github/randym/apic.png)](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:
|