apic 0.0.2 → 0.0.3
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/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
|