apic 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +54 -3
- data/app/assets/javascripts/apic/application.js +1 -0
- data/app/assets/javascripts/apic/components/endpoints.js.coffee +1 -1
- data/app/assets/javascripts/apic/components/http-headers.js.coffee +42 -7
- data/app/assets/javascripts/apic/components/xhr_history.js.coffee +3 -2
- data/app/controllers/apic/application_controller.rb +7 -2
- data/app/views/apic/application/components/_http_headers.html.slim +4 -36
- data/lib/apic.rb +20 -33
- data/lib/apic/generators/templates/apic.rb +10 -2
- data/lib/apic/route_wrapper.rb +70 -0
- data/lib/apic/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7f55ccf1ff4c22f1b24ad1969ee107cfa416030
|
4
|
+
data.tar.gz: 8080b18679726d48795dced26b908354edb83b41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d66f4291f31f76ebe2b763dabe201a45c0b2d0523f0be8db6d373c9ef2d7cb8200d8dbf3ad53b6756aae9e9852309423a35ce12ca4505f906fbac4925dcf8d2
|
7
|
+
data.tar.gz: 2a482d14f24c4aa53db611e89fa10060b981a46d0562d68c07d1511866e7af791ca1ba9d787f29c9588165ae623cf37675cd0d3dda45df6c9206696d2fa9f850
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# APIc
|
2
2
|
|
3
3
|
## What is it?
|
4
4
|
|
@@ -46,7 +46,7 @@ To make this as simple and painless as possible, APIc exposes a DSL to your cont
|
|
46
46
|
APIc knows what type of routes are available and will automatically add in the _method parameter and value for PATCH and DELETE requests.
|
47
47
|
|
48
48
|
```
|
49
|
-
class TestController
|
49
|
+
class TestController < ActionController.base
|
50
50
|
|
51
51
|
apic_action_params create: [:name, :acceptance]
|
52
52
|
|
@@ -59,7 +59,7 @@ end
|
|
59
59
|
|
60
60
|
### Initializer
|
61
61
|
|
62
|
-
The apic:install generator will add in a default intializer providing examples of the route matching and authentication filtering.
|
62
|
+
The apic:install generator will mount APIc to /apic and add in a default intializer providing examples of the route matching and authentication filtering.
|
63
63
|
|
64
64
|
```
|
65
65
|
config/initializers/apic.rb
|
@@ -76,6 +76,21 @@ For example, if you have namespecs all of your api endpoints to /api/v1/ simply
|
|
76
76
|
Apic.route_matcher = /\/api\/v1\//
|
77
77
|
```
|
78
78
|
|
79
|
+
#### Custom Headers
|
80
|
+
|
81
|
+
When you add headers in APIc we automatically create typeahead options for standard request headers.
|
82
|
+
However, many, many people define their own headers for use in a custom API. APIc lets you specify
|
83
|
+
any custom headers you want to make available to the typeahead by setting an array of header names
|
84
|
+
in the apic.rb initializer.
|
85
|
+
|
86
|
+
```
|
87
|
+
Apic.custom_headers = %w(HTTP-MY-AWESOME-HEADER HTTP-ANTOHER-AWESOME-HEADER)
|
88
|
+
```
|
89
|
+
|
90
|
+
Of course you can create any header you want in the UI, even if it is not defined as a custom header,
|
91
|
+
but for other people using this tool in your organization or even in public would probably appreciate it if
|
92
|
+
they didn't have to remember exactly what that header field name was!.
|
93
|
+
|
79
94
|
#### Authentication filters
|
80
95
|
|
81
96
|
When testing your API it is often convenient to know which routes require authentication as you will need to add those headers before sending your request.
|
@@ -85,4 +100,40 @@ If you specify in your configuration the before_filter you are using for authent
|
|
85
100
|
Apic.authentication_filter = :authenticate
|
86
101
|
```
|
87
102
|
|
103
|
+
## Requirements
|
104
|
+
|
105
|
+
APIc _should_ work on any Rails 3.2+ application out of the box.
|
106
|
+
If it doesn't, send me a pull request!!
|
107
|
+
|
108
|
+
## Roadmap
|
109
|
+
|
110
|
+
APIc is still in the very early days. I've gone with greater developer (as in me!) productivity at the cost of more dependencies
|
111
|
+
in the gem. Moving forward, I'd like to see the following:
|
112
|
+
|
113
|
+
- Rebuild views with vanilla erb so I can drop slim-rails
|
114
|
+
- Find someone who rocks at css/design and ditch bootstrap/sass
|
115
|
+
- Rewrite the jquery plugins in vanilla js so I can drop jquery and coffee
|
116
|
+
|
117
|
+
Under the 'fun' section comes
|
118
|
+
|
119
|
+
- Implement OAuth and Basic authentication as well as token caching
|
120
|
+
- Collect and display response time metrics
|
121
|
+
- Spec and Doc the crap out of it!
|
122
|
+
|
123
|
+
I guess when all that is done, APIc goes to 1.0.0
|
124
|
+
|
125
|
+
# Contribute
|
126
|
+
|
127
|
+
Just Do It!
|
128
|
+
|
88
129
|
This project rocks and uses MIT-LICENSE.
|
130
|
+
|
131
|
+
|
132
|
+
### Change log
|
133
|
+
|
134
|
+
#### 2013.10.05
|
135
|
+
- Removed the default 'api' route matching.
|
136
|
+
- Rationalized route matching to ensure that internal and apic routes are not exposed as endpoints.
|
137
|
+
- Altered history links to replay on single click instead of double click.
|
138
|
+
- added support for customized headers typeahead matching when setting a header.
|
139
|
+
|
@@ -13,7 +13,7 @@ $.fn.extend
|
|
13
13
|
|
14
14
|
$.each endpoints, (key, value) ->
|
15
15
|
option = $('<option>'+ key + '</option>')
|
16
|
-
option.text('[restricted] ' + option.text()) if value.
|
16
|
+
option.text('[restricted] ' + option.text()) if value.authentication_required
|
17
17
|
$(settings.select).append(option)
|
18
18
|
|
19
19
|
change = ->
|
@@ -1,21 +1,56 @@
|
|
1
1
|
$.fn.extend
|
2
2
|
httpHeaders: (options) ->
|
3
|
-
|
4
|
-
presets: {'Content-Type': 'application/json'}
|
3
|
+
defaults =
|
4
|
+
presets: {'Content-Type': 'application/json'},
|
5
|
+
headers: [
|
6
|
+
'Accept',
|
7
|
+
'Accept-Charset',
|
8
|
+
'Accept-Datetime',
|
9
|
+
'Accept-Encoding',
|
10
|
+
'Accept-Language',
|
11
|
+
'Authorization',
|
12
|
+
'Cache-Control',
|
13
|
+
'Connection',
|
14
|
+
'Content-Length',
|
15
|
+
'Content-MD5',
|
16
|
+
'Content-Type',
|
17
|
+
'Cookie',
|
18
|
+
'Date',
|
19
|
+
'Expect',
|
20
|
+
'From',
|
21
|
+
'Host',
|
22
|
+
'If-Match',
|
23
|
+
'If-Modified-Since',
|
24
|
+
'If-None-Match',
|
25
|
+
'If-Range',
|
26
|
+
'If-Unmodified-Since',
|
27
|
+
'Max-Forwards',
|
28
|
+
'Origin',
|
29
|
+
'Pragma',
|
30
|
+
'Proxy-Authorization',
|
31
|
+
'Range',
|
32
|
+
'Referer',
|
33
|
+
'TE',
|
34
|
+
'Upgrade',
|
35
|
+
'User-Agent',
|
36
|
+
'Via',
|
37
|
+
'Warning'
|
38
|
+
]
|
5
39
|
|
6
40
|
$.each $(this).data(), (key, value) ->
|
7
|
-
|
41
|
+
defaults[key] = $.extend defaults[key], value
|
8
42
|
|
9
|
-
settings = $.extend
|
43
|
+
settings = $.extend defaults, options
|
10
44
|
|
11
45
|
$(this).data('items', settings.presets)
|
12
46
|
|
13
47
|
self = this
|
14
48
|
|
49
|
+
$('#inputHttpHeaderFieldName').typeahead({source: settings.headers})
|
15
50
|
selected = undefined
|
16
51
|
|
17
52
|
add = ->
|
18
|
-
name = $('#
|
53
|
+
name = $('#inputHttpHeaderFieldName').val()
|
19
54
|
value = $('#inputHttpHeaderValue').val()
|
20
55
|
if !!name and !!value
|
21
56
|
tmp_items = items()
|
@@ -37,12 +72,12 @@ $.fn.extend
|
|
37
72
|
name = self.selected.data('key')
|
38
73
|
headers = items()
|
39
74
|
value = headers[name]
|
40
|
-
$('
|
75
|
+
$('inputHttpHeaderFieldName').val(name)
|
41
76
|
$('#inputHttpHeaderValue').val(value)
|
42
77
|
$('#httpHeadersModal').modal('show')
|
43
78
|
|
44
79
|
create = ->
|
45
|
-
$('#
|
80
|
+
$('#inputHttpHeaderFieldName').val('')
|
46
81
|
$('#inputHttpHeaderValue').val('')
|
47
82
|
$('#httpHeadersModal').modal('show')
|
48
83
|
|
@@ -41,8 +41,9 @@ $.fn.extend
|
|
41
41
|
else
|
42
42
|
li.removeClass('active')
|
43
43
|
|
44
|
-
|
44
|
+
$(self).on('refresh', -> refresh.apply self)
|
45
45
|
$(self).on('add', (e, item) -> add.apply self, [item])
|
46
|
-
$('.xhr-history').on('
|
46
|
+
$('.xhr-history').on('click', 'li', (e) -> replay this)
|
47
47
|
$('.toggle-history').on('click', -> show.apply self)
|
48
|
+
|
48
49
|
this
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module Apic
|
2
2
|
class ApplicationController < ActionController::Base
|
3
|
+
|
4
|
+
before_filter :custom_headers, :endpoints
|
5
|
+
|
3
6
|
def index
|
4
|
-
|
5
|
-
|
7
|
+
end
|
8
|
+
|
9
|
+
def custom_headers
|
10
|
+
@custom_headers ||= Apic::custom_headers
|
6
11
|
end
|
7
12
|
|
8
13
|
def endpoints
|
@@ -1,7 +1,7 @@
|
|
1
1
|
div.row.headers
|
2
2
|
div.http-headers-component
|
3
3
|
h4 HTTP Headers
|
4
|
-
div.http-headers
|
4
|
+
div.http-headers(data-headers="#{@custom_headers}")
|
5
5
|
ul.http-headers-list.nav.nav-list
|
6
6
|
|
7
7
|
div.http-headers-controls
|
@@ -18,45 +18,13 @@ div.row.headers
|
|
18
18
|
div.modal-body
|
19
19
|
form.form-horizontal
|
20
20
|
div.control-group
|
21
|
-
label.control-label(for='
|
21
|
+
label.control-label(for='inputHttpHeaderFieldName') Header
|
22
22
|
div.controls
|
23
|
-
|
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
|
23
|
+
input#inputHttpHeaderFieldName
|
56
24
|
div.control-group
|
57
25
|
label.control-label(for='inputHttpHeaderValue') Value
|
58
26
|
div.controls
|
59
|
-
input.input-xxlarge(type='text'
|
27
|
+
input.input-xxlarge#inputHttpHeaderValue(type='text' placeholder='value')
|
60
28
|
|
61
29
|
div.modal-footer
|
62
30
|
a.btn(href='#' data-dismiss='modal') Cancel
|
data/lib/apic.rb
CHANGED
@@ -2,52 +2,39 @@ require 'apic/params_cache'
|
|
2
2
|
require "apic/extension"
|
3
3
|
require "apic/engine"
|
4
4
|
require "apic/generators/install_generator"
|
5
|
+
require 'apic/route_wrapper'
|
5
6
|
module Apic
|
6
7
|
|
7
8
|
mattr_accessor :authentication_filter
|
8
9
|
@@authentication_filter = nil
|
9
10
|
|
10
11
|
mattr_accessor :route_matcher
|
11
|
-
@@route_matcher =
|
12
|
+
@@route_matcher = /.*/
|
12
13
|
|
14
|
+
mattr_accessor :custom_headers
|
15
|
+
@@custom_headers = []
|
13
16
|
|
17
|
+
class << self
|
14
18
|
|
15
|
-
|
16
|
-
|
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
|
19
|
+
def endpoints
|
20
|
+
@endpoints ||= endpoints_hash
|
34
21
|
end
|
35
|
-
end
|
36
22
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
23
|
+
private
|
24
|
+
|
25
|
+
def endpoints_hash
|
26
|
+
Hash.new do |hash, route|
|
27
|
+
wrapper = RouteWrapper.new(route)
|
28
|
+
hash[wrapper.endpoint] = wrapper.to_h unless wrapper.internal?
|
29
|
+
end.tap do |hash|
|
30
|
+
Rails.application.routes.routes.each do |route|
|
31
|
+
if route.path.spec.to_s =~ @@route_matcher
|
32
|
+
hash[route]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
44
36
|
end
|
45
37
|
end
|
46
|
-
|
47
|
-
def self.template_for(controller, action)
|
48
|
-
(controller + '_controller').camelize.constantize
|
49
|
-
Apic::ParamsCache.params_for(controller, action) || []
|
50
|
-
end
|
51
38
|
end
|
52
39
|
|
53
40
|
|
@@ -1,10 +1,18 @@
|
|
1
1
|
# Specify a route matcher to restrict which application routes are available
|
2
2
|
# in the console. By default all routes will be loaded
|
3
3
|
#
|
4
|
-
# Apic.route_matcher =
|
4
|
+
# Apic.route_matcher = /.*/
|
5
5
|
#
|
6
6
|
#
|
7
|
-
# Specify your authentication filter.
|
7
|
+
# Specify your authentication filter.
|
8
|
+
# Requests that use this filter will be marked
|
8
9
|
# as restricted in the Api endpoints list.
|
9
10
|
#
|
10
11
|
# Apic.authentication_filter = :authenticate
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# Declare custom headers.
|
15
|
+
# These headers are added to the list of matches in the UI's typeahead
|
16
|
+
# used to set headers for requests.
|
17
|
+
#
|
18
|
+
# Apic.custom_headers = %w(Total-Awesomeness Http-More-Awesome-Than-Awesome)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Apic
|
4
|
+
class RouteWrapper < SimpleDelegator
|
5
|
+
|
6
|
+
def to_h
|
7
|
+
endpoint = {
|
8
|
+
path: path,
|
9
|
+
parts: parts - [:format],
|
10
|
+
verb: verb,
|
11
|
+
template: template,
|
12
|
+
key: key,
|
13
|
+
authentication_required: authentication_required
|
14
|
+
}
|
15
|
+
|
16
|
+
if %(PATCH DELETE).include? verb
|
17
|
+
endpoint[:template] << '_method'
|
18
|
+
end
|
19
|
+
|
20
|
+
endpoint
|
21
|
+
end
|
22
|
+
|
23
|
+
def endpoint
|
24
|
+
[verb, path].join(' ')
|
25
|
+
end
|
26
|
+
|
27
|
+
def internal?
|
28
|
+
requirements[:controller].to_s =~ %r{\Arails/(info|welcome)} ||
|
29
|
+
path =~ %r{\A#{Rails.application.config.assets.prefix}} ||
|
30
|
+
path =~ %r{\A\/apic}
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def authentication_required
|
36
|
+
return false unless Apic.authentication_filter
|
37
|
+
controller._process_action_callbacks.any? do |callback|
|
38
|
+
eval <<-RUBY_EVAL
|
39
|
+
#{callback.filter == Apic.authentication_filter} && #{callback.instance_values['compiled_options']}
|
40
|
+
RUBY_EVAL
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def controller
|
45
|
+
if controller = requirements[:controller]
|
46
|
+
[controller.to_s, 'controller'].join('_').camelize.constantize
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def verb
|
51
|
+
super.source.gsub(/[$^]/, '')
|
52
|
+
end
|
53
|
+
|
54
|
+
def path
|
55
|
+
super.spec.to_s.gsub("(.:format)",".json")
|
56
|
+
end
|
57
|
+
|
58
|
+
def action_name
|
59
|
+
requirements[:action]
|
60
|
+
end
|
61
|
+
|
62
|
+
def key
|
63
|
+
[verb, path].join(' ')
|
64
|
+
end
|
65
|
+
|
66
|
+
def template
|
67
|
+
Apic::ParamsCache.params_for(controller, action_name) || []
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/apic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Randy Morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -94,8 +94,9 @@ dependencies:
|
|
94
94
|
- - '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
description:
|
98
|
-
|
97
|
+
description: APIc is a bolt on API console for Rails 3+ applications. It rounds up
|
98
|
+
your endpoints and makes it dead easy to configure, send, review and replay any
|
99
|
+
request.
|
99
100
|
email:
|
100
101
|
- digital.ipseity@gmail.com
|
101
102
|
executables: []
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- lib/apic/generators/install_generator.rb
|
129
130
|
- lib/apic/generators/templates/apic.rb
|
130
131
|
- lib/apic/params_cache.rb
|
132
|
+
- lib/apic/route_wrapper.rb
|
131
133
|
- lib/apic/version.rb
|
132
134
|
- lib/apic.rb
|
133
135
|
- lib/tasks/apic_tasks.rake
|