apic 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f34a4f4aab7e80104a44cadc30f087c953b02f26
4
- data.tar.gz: f3f170ca3ddf9ce1d90bdc222a9f31786dbf91e6
3
+ metadata.gz: 62e91d7da069396fc04033442798fcfa93717c2e
4
+ data.tar.gz: 09884be511addc4b3a701d8a16ce9e1373a08358
5
5
  SHA512:
6
- metadata.gz: 43bf31780842c732681233c1e55a9b2abbcb20a25d6182b80b5c6fa30f082d0143df9a3442f2dced1eb01596b2495f3bde042662cf5dfab4e2a088571e939891
7
- data.tar.gz: 0779a4e019559f14b99e10a0bfc7d463ff4ae2e42380438c6aa3dcdf5e4f6e51fd33163a1defa4ab8b589b738d120cd7897d91e103098d446f10cdcfa6b4928c
6
+ metadata.gz: 34c1269243b0ffe1e7908d577a8776703445a62dfd1cd4aea88a88f2d166e964580c7d4420d2a83296324709b3f8721364fcbb79b2e04f7f62bf97ad538c0a09
7
+ data.tar.gz: 4353172bb5077836055d5778326664e3b05a84a6347b4026d3c6f9ed4a65a0fff394e614d997d71bd35cd2ea08b733c8766b332bd72978f49fb09307787a162b
data/README.md CHANGED
@@ -1,7 +1,12 @@
1
- = Apic
1
+ = APIc
2
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)
3
+ ## What is it?
4
4
 
5
+ APIc is a bolt on API console for Rails 3+ applications.
6
+ It rounds up your endpoints and makes it dead easy to configure, send, review and replay any request.
7
+
8
+
9
+ ![Screen 1](https://github.com/randym/apic/raw/master/sample.png)
5
10
 
6
11
  What you need to do?
7
12
 
@@ -11,35 +16,73 @@ add the gem to your Gemfile
11
16
  gem 'apic'
12
17
  ```
13
18
 
14
- require the gem in your application.rb
19
+ Run the generator!
15
20
 
16
21
  ```
17
- require 'apic'
22
+ rails generate apic:install
18
23
  ```
19
24
 
20
- mount the gem in your routes.rb
25
+ If you are using bundler:
21
26
 
22
27
  ```
23
- mount Apic::Engine => "/apic"
28
+ bundle exec rails generate apic:install
29
+
24
30
  ```
25
31
 
26
- ## and some groovy stuff too
32
+ Spin up your Rails application and navigate to
33
+
34
+ ```
35
+ localhost:3000/apic
36
+ ```
27
37
 
28
- Filter routes on a regex match
29
38
 
30
39
 
40
+ ## Configuration
41
+
42
+ ### Controller Parameters
43
+
44
+ APIc needs to know about the parameters your PUT, PATCH and UPDATE requests require.
45
+ To make this as simple and painless as possible, APIc exposes a DSL to your controllers so you can specify what you need.
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
+
31
48
  ```
32
- Apic.routes_matcher = /\/api\//
49
+ class TestController << ActionController.base
50
+
51
+ apic_action_params create: [:name, :acceptance]
52
+
53
+ def create
54
+ # all your cool stuff that creates a new object
55
+ end
56
+
57
+ end
58
+ ```
59
+
60
+ ### Initializer
61
+
62
+ The apic:install generator will add in a default intializer providing examples of the route matching and authentication filtering.
63
+
33
64
  ```
65
+ config/initializers/apic.rb
66
+ ```
67
+
68
+ #### Route Matching
69
+
70
+ APIc will load all routes in your rails app by default under the assumption that you are building your api as a dedicated service.
71
+ If this is not the case, you can specify a matching regular expression that APIc will use to find your API routes.
34
72
 
35
- Tell us what your authorization filter is!
73
+ For example, if you have namespecs all of your api endpoints to /api/v1/ simply uncomment out the Apic.routes_matcher line in config/initializers/apic.rb
36
74
 
37
75
  ```
38
- Apic.authorization_filter = :authenticate
76
+ Apic.route_matcher = /\/api\/v1\//
39
77
  ```
40
78
 
79
+ #### Authentication filters
41
80
 
42
- git remote add origin https://github.com/randym/apic.git
81
+ 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.
82
+ If you specify in your configuration the before_filter you are using for authentication APIc will mark those routes as restricted.
43
83
 
84
+ ```
85
+ Apic.authentication_filter = :authenticate
86
+ ```
44
87
 
45
88
  This project rocks and uses MIT-LICENSE.
@@ -2,4 +2,5 @@ $(document).ready ->
2
2
  $('.http-headers').httpHeaders()
3
3
  $('.endpoints-component').endpoints()
4
4
  $('.console').apic_console(host: $('.console').data('host'))
5
+ $('.xhr-history').xhr_history()
5
6
  true
@@ -9,6 +9,7 @@ $.fn.extend
9
9
  params: '.parameter',
10
10
  console: '.console',
11
11
  console_log: '.console-log',
12
+ history: '.xhr-history',
12
13
  host: 'localhost:3000',
13
14
  request_timeout: 10000,
14
15
  timeout_callback: null,
@@ -16,6 +17,8 @@ $.fn.extend
16
17
 
17
18
  self = this
18
19
 
20
+ history = []
21
+
19
22
  settings = $.extend settings, options
20
23
 
21
24
  log_timeline = (method, uri) ->
@@ -25,13 +28,14 @@ $.fn.extend
25
28
 
26
29
  log_request = (xhr) ->
27
30
  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
31
 
34
- log_message = (title, message) ->
32
+ $(settings.console_log).empty()
33
+ log_item "Request URL", uri()
34
+ log_item "Request Method", endpoint().verb
35
+ log_item "Response Code", [xhr.status, xhr.statusText].join(' ')
36
+ log_item "Request Headers", xhr.getAllResponseHeaders()
37
+
38
+ log_item = (title, message) ->
35
39
  $(settings.console_log).append('<div><span class="log-header">' + title + '</span>:<span class="log-data"> ' + message + '</span></div>')
36
40
 
37
41
  duration = ->
@@ -57,7 +61,6 @@ $.fn.extend
57
61
  path += query_string()
58
62
  path
59
63
 
60
- $('#do-me').on('click', -> send.apply self)
61
64
 
62
65
  value_for = (name) ->
63
66
  $(settings.params + ' [name="' + name + '"]').val()
@@ -89,14 +92,19 @@ $.fn.extend
89
92
  $(settings.console).text(xhr.responseText)
90
93
 
91
94
  log_request xhr
95
+ record(xhr)
92
96
 
93
97
  onerror = (response) ->
94
98
  console.log response
95
99
 
96
- request = () ->
100
+ request = (endpoint, headers, uri) ->
97
101
  xhr = new XMLHttpRequest
98
- xhr.open endpoint().verb, uri()
99
- set_headers xhr
102
+ xhr.open endpoint.verb, uri, true
103
+ $.each headers, (key, value) ->
104
+ if key is 'Authorization'
105
+ xhr.withCredentials = true
106
+ xhr.setRequestHeader(key, value)
107
+
100
108
  xhr.onerror = (xhr) ->
101
109
  onerror.apply self, [xhr]
102
110
  xhr.onload = (response) ->
@@ -105,6 +113,8 @@ $.fn.extend
105
113
 
106
114
  set_headers = (xhr) ->
107
115
  $.each headers(), (key, value) ->
116
+ if key is 'Authorization'
117
+ xhr.withCredentials = true
108
118
  xhr.setRequestHeader(key, value)
109
119
 
110
120
  validate_params = () ->
@@ -112,14 +122,34 @@ $.fn.extend
112
122
  for part in endpoint().parts
113
123
  if value_for(part) is ""
114
124
  missing.push(part)
115
- if missing.length > 0
116
- alert('url parts reqired: ' + missing)
125
+ if missing.length > 0
126
+ alert('url parts reqired: ' + missing)
117
127
  missing.length is 0
118
128
 
119
- send = () ->
129
+ record = (xhr) ->
130
+ history_item =
131
+ endpoint: endpoint()
132
+ headers: headers()
133
+ body: body()
134
+ uri: uri()
135
+ xhr: xhr
136
+
137
+ $(settings.history).trigger('add', [history_item])
138
+
139
+ send = (_point, _head, _bod, _u) ->
140
+ _point ||= endpoint()
141
+ _head ||= headers()
142
+ _bod ||= body()
143
+ _u ||= uri()
144
+
120
145
  if validate_params()
121
- xhr = request()
122
- if endpoint().verb is 'GET'
146
+ xhr = request(_point, _head, _u)
147
+ if _point.verb is 'GET'
123
148
  xhr.send()
124
149
  else
125
- xhr.send JSON.stringify(body)
150
+ data = JSON.stringify(_bod)
151
+ xhr.send(data)
152
+
153
+ $('#do-me').on('click', -> send.apply self, [null])
154
+ $(self).on('send', (e, point, head, bod, u) -> send.apply self, [point, head, bod, u])
155
+ true
@@ -13,7 +13,6 @@ $.fn.extend
13
13
 
14
14
  $.each endpoints, (key, value) ->
15
15
  option = $('<option>'+ key + '</option>')
16
- console.log value
17
16
  option.text('[restricted] ' + option.text()) if value.authorization_required
18
17
  $(settings.select).append(option)
19
18
 
@@ -32,7 +31,7 @@ $.fn.extend
32
31
  el.find('#input-_method').val(endpoint.verb.toLowerCase())
33
32
 
34
33
  selected = ->
35
- endpoints[$(settings.select).val()]
34
+ endpoints[$(settings.select).val().replace('[restricted] ', '')]
36
35
 
37
36
  field_set_for = (name, options={}) ->
38
37
  clone = $(self).find(settings.template).clone()
@@ -1,7 +1,7 @@
1
1
  $.fn.extend
2
2
  httpHeaders: (options) ->
3
3
  settings =
4
- presets: {}
4
+ presets: {'Content-Type': 'application/json'}
5
5
 
6
6
  $.each $(this).data(), (key, value) ->
7
7
  settings[key] = value
@@ -0,0 +1,48 @@
1
+
2
+ $.fn.extend
3
+
4
+ xhr_history: (options) ->
5
+ defaults = {}
6
+ self = this
7
+ $(self).data('items', [])
8
+
9
+ refresh = ->
10
+ $(self).empty()
11
+ $.each items(), (index, item) ->
12
+ el = list_item(item)
13
+ el.data('request', item)
14
+
15
+ $(self).append el
16
+
17
+ list_item = (item) ->
18
+ $('<li class="xhr-history-item ' + item.xhr.statusText.toLowerCase() + '"><a href="#"><i class="icon-refresh icon-white ' + item.xhr.statusText.toLowerCase() + '"/><i>' + item.xhr.status + ' '+ item.endpoint.verb + ' ' + item.uri + '</span></a></li>')
19
+
20
+ items = ->
21
+ $(self).data('items')
22
+
23
+ add = (item)->
24
+ i = items()
25
+ i.push item
26
+ $(self).data('items',i)
27
+ refresh()
28
+
29
+ replay = (el) ->
30
+ request = $(el).data('request')
31
+ $('.console').trigger('send', [request.endpoint, request.headers, request.body, request.uri])
32
+ console.log($(el).data('request'))
33
+
34
+ show = ->
35
+ el = $('.history')
36
+ el.toggle()
37
+
38
+ li = $(event.target).closest('li')
39
+ if $(el).is(':visible')
40
+ li.addClass('active')
41
+ else
42
+ li.removeClass('active')
43
+
44
+ #$(self).on('refresh', -> refresh.apply self)
45
+ $(self).on('add', (e, item) -> add.apply self, [item])
46
+ $('.xhr-history').on('dblclick', 'li', (e) -> replay this)
47
+ $('.toggle-history').on('click', -> show.apply self)
48
+ this
@@ -10,9 +10,6 @@
10
10
  margin-left: 10px;
11
11
  min-height: 130px;
12
12
  overflow-y: scroll;
13
- h4 {
14
- text-align: center;
15
- }
16
13
  .http-headers {
17
14
  ul {
18
15
  border: 1px solid #eee;
@@ -0,0 +1,16 @@
1
+ .history {
2
+ display: none;
3
+ border-top: 1px solid #DDD;
4
+ padding: 5px;
5
+ }
6
+ .xhr-history {
7
+ list-style-type: none;
8
+ i.forbidden {
9
+ background-color: red;
10
+ margin-right: 5px;
11
+ }
12
+ i.ok {
13
+ background-color: green;
14
+ margin-right: 5px;
15
+ }
16
+ }
@@ -1,4 +1,12 @@
1
1
  module Apic
2
2
  class ApplicationController < ActionController::Base
3
+ def index
4
+ Rails.logger.debug endpoints
5
+ endpoints
6
+ end
7
+
8
+ def endpoints
9
+ @endpoints ||= Apic.endpoints
10
+ end
3
11
  end
4
12
  end
@@ -7,3 +7,5 @@ div.navbar.navbar-inverse.navbar-fixed-top
7
7
  a(href="#headers") Headers
8
8
  li.edit-endpoints.active
9
9
  a(href="#endpoints") Endpoints
10
+ li.toggle-history
11
+ a(href='#history') History
@@ -5,7 +5,7 @@ div.endpoints-component( data-endpoints="#{@endpoints.to_json}")
5
5
  div.control-group
6
6
  label.control-label(for="selectEndpoint") Api Endpoint
7
7
  div.controls
8
- select(id='selectEndpoint')
8
+ select.input-xxlarge(id='selectEndpoint')
9
9
 
10
10
  div.control-group.template
11
11
  label.control-label(for="inputParam") Param Name
@@ -0,0 +1,2 @@
1
+ h4 History
2
+ ul.xhr-history
@@ -8,3 +8,5 @@ div.container
8
8
  button#do-me.btn.btn-primary(href='#') Send
9
9
  div.row
10
10
  == render :partial => "apic/application/components/console"
11
+ div.row.history
12
+ == render :partial => "apic/application/components/xhr_history"
data/config/routes.rb CHANGED
@@ -1,3 +1,12 @@
1
- Apic::Engine.routes.draw do
2
- root "#index"
1
+ if Rails.version < '4.0.0'
2
+
3
+ Apic::Engine.routes.draw do
4
+ match "/" => "application#index"
5
+ end
6
+ else
7
+
8
+
9
+ Apic::Engine.routes.draw do
10
+ get "/" => "application#index"
11
+ end
3
12
  end
data/lib/apic/engine.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module Apic
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace Apic
4
+ require 'slim'
4
5
  require 'jquery-rails'
5
6
  require 'bootstrap-sass'
6
7
  ActiveSupport.on_load(:action_controller) do
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+ module Apic
3
+ module Generators
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../../generators/templates", __FILE__)
6
+
7
+ desc "creates initializer and add engine mount point to your routes"
8
+
9
+ def copy_initializer
10
+ template 'apic.rb', 'config/initializers/apic.rb'
11
+ end
12
+
13
+ def mount_engine
14
+ if Rails.version < '4.0.0'
15
+ route 'mount Apic::Engine, :at => "/apic"'
16
+ else
17
+ route 'mount Apic::Engine => "/apic"'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ # Specify a route matcher to restrict which application routes are available
2
+ # in the console. By default all routes will be loaded
3
+ #
4
+ # Apic.route_matcher = /\/api\/v1\//
5
+ #
6
+ #
7
+ # Specify your authentication filter. Requests that use this filter will be marked
8
+ # as restricted in the Api endpoints list.
9
+ #
10
+ # Apic.authentication_filter = :authenticate
data/lib/apic/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Apic
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/apic.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  require 'apic/params_cache'
2
2
  require "apic/extension"
3
3
  require "apic/engine"
4
-
4
+ require "apic/generators/install_generator"
5
5
  module Apic
6
6
 
7
- mattr_accessor :authorization_filter
8
- @@authorization_filter = nil
7
+ mattr_accessor :authentication_filter
8
+ @@authentication_filter = nil
9
9
 
10
10
  mattr_accessor :route_matcher
11
11
  @@route_matcher = /\/api\//
@@ -35,12 +35,11 @@ module Apic
35
35
  end
36
36
 
37
37
  def self.requires_authorization(controller, action_name)
38
- return false unless @@authorization_filter
38
+ return false unless @@authentication_filter
39
39
  controller = (controller + '_controller').camelize.constantize
40
40
  controller._process_action_callbacks.any? do |callback|
41
- p @@authorization_filter
42
41
  eval <<-RUBY_EVAL
43
- #{callback.filter == @@authorization_filter} && #{callback.instance_values['compiled_options']}
42
+ #{callback.filter == @@authentication_filter} && #{callback.instance_values['compiled_options']}
44
43
  RUBY_EVAL
45
44
  end
46
45
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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-01 00:00:00.000000000 Z
11
+ date: 2013-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: 4.0.0
19
+ version: 3.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: 4.0.0
26
+ version: 3.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: slim-rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -104,25 +104,29 @@ extra_rdoc_files: []
104
104
  files:
105
105
  - app/assets/javascripts/apic/apic.js.coffee
106
106
  - app/assets/javascripts/apic/application.js
107
- - app/assets/javascripts/apic/components/console.js.coffee
107
+ - app/assets/javascripts/apic/components/apic_console.js.coffee
108
108
  - app/assets/javascripts/apic/components/endpoints.js.coffee
109
109
  - app/assets/javascripts/apic/components/http-headers.js.coffee
110
+ - app/assets/javascripts/apic/components/xhr_history.js.coffee
110
111
  - app/assets/stylesheets/apic/application.css.scss
111
112
  - app/assets/stylesheets/apic/components/console.css.scss
112
113
  - app/assets/stylesheets/apic/components/endpoints.css.scss
113
114
  - app/assets/stylesheets/apic/components/http-headers.css.scss
115
+ - app/assets/stylesheets/apic/components/xhr-history.css.scss
114
116
  - app/controllers/apic/application_controller.rb
115
- - app/controllers/apic/controller.rb
116
117
  - app/helpers/apic/application_helper.rb
117
118
  - app/views/apic/application/_navigation.html.slim
118
119
  - app/views/apic/application/components/_console.html.slim
119
120
  - app/views/apic/application/components/_endpoints.html.slim
120
121
  - app/views/apic/application/components/_http_headers.html.slim
122
+ - app/views/apic/application/components/_xhr_history.html.slim
121
123
  - app/views/apic/application/index.html.slim
122
124
  - app/views/layouts/apic/application.html.erb
123
125
  - config/routes.rb
124
126
  - lib/apic/engine.rb
125
127
  - lib/apic/extension.rb
128
+ - lib/apic/generators/install_generator.rb
129
+ - lib/apic/generators/templates/apic.rb
126
130
  - lib/apic/params_cache.rb
127
131
  - lib/apic/version.rb
128
132
  - lib/apic.rb
@@ -1,13 +0,0 @@
1
- module Apic
2
- class Controller < ApplicationController
3
-
4
-
5
- def index
6
- endpoints
7
- end
8
-
9
- def endpoints
10
- @endpoints ||= Apic.endpoints
11
- end
12
- end
13
- end