rack-api 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .DS_Store
2
2
  pkg
3
3
  tmp
4
+ docs
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-api (0.1.0)
4
+ rack-api (0.1.1)
5
5
  activesupport (~> 3.0.6)
6
6
  rack (~> 1.2.1)
7
7
  rack-mount (~> 0.6.14)
@@ -24,8 +24,106 @@ Create web app APIs that respond to one or more formats using an elegant DSL.
24
24
  end
25
25
  end
26
26
 
27
+ === Rails Integration
28
+
29
+ First, set up your Gemfile like this:
30
+
31
+ gem "rack-api", "~> 0.1.0", :require => "rack/api"
32
+
33
+ Create your API somewhere. In this example, we'll add it to <tt>lib/api.rb</tt>.
34
+
35
+ Rack::API.app do
36
+ prefix "api"
37
+
38
+ version :v1 do
39
+ get "status(.:format)" do
40
+ {:success => true, :time => Time.now}
41
+ end
42
+ end
43
+ end
44
+
45
+ Load this file somehow. I'd create a <tt>config/initializers/dependencies.rb</tt> with something like
46
+
47
+ require "lib/api"
48
+
49
+ Finally, you can set up the API routing. Open <tt>config/routes.rb</tt> and add the following line:
50
+
51
+ mount Rack::API => "/"
52
+
53
+ If you define your API by inheriting from the Rack::API class, remember to mount your class instead.
54
+
55
+ mount MyAPI => "/"
56
+
27
57
  For additional examples, see https://github.com/fnando/rack-api/tree/master/examples.
28
58
 
59
+ === Using RSpec with Rack::API
60
+
61
+ You can easily test Rack::API apps by using Rack::Test. This applies to both RSpec and Test Unit. See what you need to do if you want to use it with RSpec.
62
+
63
+ First, open your <tt>spec/spec_helper.rb</tt> and add something like this:
64
+
65
+ require "rspec"
66
+ require "rack/test"
67
+
68
+ RSpec.configure do |config|
69
+ config.include Rack::Test::Methods
70
+ end
71
+
72
+ Then you can go to your spec file, say, <tt>spec/api_spec.rb</tt>. You need to define a helper method called +app+, which will point to your Rack::API (the class itself or your own class).
73
+
74
+ require "spec_helper"
75
+
76
+ describe Rack::API do
77
+ # Remember to use your own class if you
78
+ # inherited from Rack::API
79
+ def app; Rack::API; end
80
+
81
+ it "renders status page" do
82
+ get "/api/v1/status"
83
+ JSON.load(last_response.body).should == {:status => "running"}
84
+ last_response.status.should == 200
85
+ end
86
+ end
87
+
88
+ If you want to do expectations over basic authentication, you'll have some like this:
89
+
90
+ require "spec_helper"
91
+
92
+ describe Rack::API do
93
+ def basic_auth(username, password)
94
+ "Basic " + Base64.encode64("#{username}:#{password}")
95
+ end
96
+
97
+ it "requires authentication" do
98
+ get "/api/v1/status"
99
+ last_response.status.should == 401
100
+ end
101
+
102
+ it "grants access" do
103
+ get "/api/v1/status", {"HTTP_AUTHORIZATION" => basic_auth("john", "test")}
104
+ last_response.status.should == 200
105
+ end
106
+ end
107
+
108
+ To reduce duplication, you can move both <tt>basic_auth</tt> and <tt>app</tt> methods to a module, which will be included on RSpec.
109
+
110
+ RSpec.configure do |config|
111
+ config.include Rack::Test::Methods
112
+ config.include Helpers
113
+ end
114
+
115
+ Your <tt>Helpers</tt> module may look like this:
116
+
117
+ module Helpers
118
+ def app
119
+ Rack::API
120
+ end
121
+
122
+ def basic_auth(username, password)
123
+ "Basic " + Base64.encode64("#{username}:#{password}")
124
+ end
125
+ end
126
+
29
127
  == Maintainer
30
128
 
31
129
  * Nando Vieira (http://nandovieira.com.br)
data/Rakefile CHANGED
@@ -3,3 +3,10 @@ Bundler::GemHelper.install_tasks
3
3
 
4
4
  require "rspec/core/rake_task"
5
5
  RSpec::Core::RakeTask.new
6
+
7
+ require "rake/rdoctask"
8
+ Rake::RDocTask.new do |t|
9
+ t.rdoc_dir = "docs"
10
+ t.main = "README.rdoc"
11
+ t.rdoc_files.include "README.rdoc", *Dir["lib/**/*.rb"]
12
+ end
@@ -0,0 +1,32 @@
1
+ $:.push(File.dirname(__FILE__) + "/../lib")
2
+
3
+ # Just run `ruby examples/formats.rb` and then use something like
4
+ # `curl http://localhost:2345/api/v1/hello.xml`.
5
+
6
+ require "rack/api"
7
+ require "active_support/all"
8
+
9
+ module Rack
10
+ class API
11
+ module Formatter
12
+ class Xml < Base
13
+ def to_format
14
+ object.to_xml(:root => :messages)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ Rack::API.app do
22
+ prefix "api"
23
+ respond_to :xml
24
+
25
+ version :v1 do
26
+ get "/hello(.:format)" do
27
+ {:message => "Hello from Rack API"}
28
+ end
29
+ end
30
+ end
31
+
32
+ Rack::Handler::Thin.run Rack::API, :Port => 2345
@@ -0,0 +1,19 @@
1
+ $:.push(File.dirname(__FILE__) + "/../lib")
2
+
3
+ # Just run `ruby examples/formats.rb` and then use something like
4
+ # `curl http://localhost:2345/api/v1/hello.json` or
5
+ # `curl http://localhost:2345/api/v1/hello.jsonp?callback=myJSHandler`.
6
+
7
+ require "rack/api"
8
+
9
+ Rack::API.app do
10
+ prefix "api"
11
+
12
+ version :v1 do
13
+ get "/hello(.:format)" do
14
+ {:message => "Hello from Rack API"}
15
+ end
16
+ end
17
+ end
18
+
19
+ Rack::Handler::Thin.run Rack::API, :Port => 2345
@@ -3,15 +3,23 @@ require "rack/mount"
3
3
  require "active_support/hash_with_indifferent_access"
4
4
  require "json"
5
5
  require "logger"
6
+ require "forwardable"
6
7
 
7
8
  module Rack
8
9
  class API
9
10
  autoload :App, "rack/api/app"
10
11
  autoload :Formatter, "rack/api/formatter"
12
+ autoload :Middleware, "rack/api/middleware"
11
13
  autoload :Runner, "rack/api/runner"
12
14
  autoload :Response, "rack/api/response"
13
15
  autoload :Version, "rack/api/version"
14
16
 
17
+ class << self
18
+ extend Forwardable
19
+
20
+ def_delegators :runner, :version, :use, :prefix, :basic_auth, :helper, :respond_to
21
+ end
22
+
15
23
  # A shortcut for defining new APIs. Instead of creating a
16
24
  # class that inherits from Rack::API, you can simply pass a
17
25
  # block to the Rack::API.app method.
@@ -25,41 +33,6 @@ module Rack
25
33
  runner
26
34
  end
27
35
 
28
- # Add a middleware to the stack execution.
29
- #
30
- # Rack::API.app do
31
- # use MyMiddleware
32
- # end
33
- #
34
- def self.use(m)
35
- runner.use(m)
36
- end
37
-
38
- # Create a new API version.
39
- #
40
- # Rack::API.app do
41
- # version "v1" do
42
- # # define your API
43
- # end
44
- # end
45
- #
46
- def self.version(name, &block)
47
- runner.version(name, &block)
48
- end
49
-
50
- # Set an additional url prefix.
51
- #
52
- # Rack::API.app do
53
- # prefix "api"
54
- # version("v1") {}
55
- # end
56
- #
57
- # This API will be available through <tt>/api/v1</tt> path.
58
- #
59
- def self.prefix(name)
60
- runner.prefix(name)
61
- end
62
-
63
36
  # Reset all API definitions while using the Rack::API.app method.
64
37
  #
65
38
  def self.reset!
@@ -117,6 +117,15 @@ module Rack
117
117
  @headers = nil
118
118
  end
119
119
 
120
+ # Return credentials for Basic Authentication request.
121
+ #
122
+ def credentials
123
+ @credentials ||= begin
124
+ request = Rack::Auth::Basic::Request.new(env)
125
+ request.provided? ? request.credentials : []
126
+ end
127
+ end
128
+
120
129
  # Render the result of block.
121
130
  #
122
131
  def call(env) # :nodoc:
@@ -0,0 +1,7 @@
1
+ module Rack
2
+ class API
3
+ module Middleware
4
+ autoload :Format, "rack/api/middleware/format"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ module Rack
2
+ class API
3
+ module Middleware
4
+ class Format
5
+ def initialize(app, formats)
6
+ @app, @formats = app, formats.collect {|f| f.to_s}
7
+ end
8
+
9
+ def call(env)
10
+ request = Rack::Request.new(env)
11
+ params = request.env["rack.routing_args"].merge(request.params)
12
+ requested_format = params.fetch(:format, "json")
13
+
14
+ if @formats.include?(requested_format)
15
+ @app.call(env)
16
+ else
17
+ [406, {"Content-Type" => "text/plain"}, ["Invalid format"]]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,22 +7,76 @@ module Rack
7
7
 
8
8
  def initialize
9
9
  @settings = {
10
- :prefix => "/",
11
- :formats => %w[json jsonp],
12
- :middlewares => []
10
+ :middlewares => [],
11
+ :helpers => [],
12
+ :global => {
13
+ :prefix => "/",
14
+ :formats => %w[json jsonp],
15
+ :middlewares => [],
16
+ :helpers => []
17
+ }
13
18
  }
14
19
  end
15
20
 
21
+ # Set configuration based on scope. When defining values outside version block,
22
+ # will set configuration using <tt>settings[:global]</tt> namespace.
23
+ #
24
+ # Use the Rack::API::Runner#option method to access a given setting.
25
+ #
26
+ def set(name, value, mode = :override)
27
+ target = settings[:version] ? settings : settings[:global]
28
+
29
+ if mode == :override
30
+ target[name] = value
31
+ else
32
+ target[name] << value
33
+ end
34
+ end
35
+
36
+ # Try to fetch local configuration, defaulting to the global setting.
37
+ # Return +nil+ when no configuration is defined.
38
+ #
39
+ def option(name, mode = :any)
40
+ if mode == :merge && (settings[name].kind_of?(Array) || settings[:global][name].kind_of?(Array))
41
+ settings[:global].fetch(name, []) | settings.fetch(name, [])
42
+ else
43
+ settings.fetch(name, settings[:global][name])
44
+ end
45
+ end
46
+
16
47
  # Add a middleware to the execution stack.
17
48
  #
49
+ # Global middlewares will be merged with local middlewares.
50
+ #
51
+ # Rack::API.app do
52
+ # use ResponseTime
53
+ #
54
+ # version :v1 do
55
+ # use Gzip
56
+ # end
57
+ # end
58
+ #
59
+ # The middleware stack will be something like <tt>[ResponseTime, Gzip]</tt>.
60
+ #
18
61
  def use(middleware, *args)
19
- settings[:middlewares] << [middleware, *args]
62
+ set :middlewares, [middleware, *args], :append
20
63
  end
21
64
 
22
65
  # Set an additional url prefix.
23
66
  #
24
67
  def prefix(name)
25
- settings[:prefix] = name
68
+ set :prefix, name
69
+ end
70
+
71
+ # Add a helper to application.
72
+ #
73
+ # helper MyHelpers
74
+ # helper { }
75
+ #
76
+ def helper(mod = nil, &block)
77
+ mod = Module.new(&block) if block_given?
78
+ raise ArgumentError, "you need to pass a module or block" unless mod
79
+ set :helpers, mod, :append
26
80
  end
27
81
 
28
82
  # Create a new API version.
@@ -48,8 +102,34 @@ module Rack
48
102
  # User.authenticate(user, pass)
49
103
  # end
50
104
  # end
105
+ #
106
+ # You can disable basic authentication by providing <tt>:none</tt> as
107
+ # realm.
108
+ #
109
+ # Rack::API.app do
110
+ # basic_auth "Protected Area" do |user, pass|
111
+ # User.authenticate(user, pass)
112
+ # end
113
+ #
114
+ # version :v1 do
115
+ # # this version is protected by the
116
+ # # global basic auth block above.
117
+ # end
118
+ #
119
+ # version :v2 do
120
+ # basic_auth :none
121
+ # # this version is now public
122
+ # end
123
+ #
124
+ # version :v3 do
125
+ # basic_auth "Admin" do |user, pass|
126
+ # user == "admin" && pass == "test"
127
+ # end
128
+ # end
129
+ # end
130
+ #
51
131
  def basic_auth(realm = "Restricted Area", &block)
52
- settings[:auth] = [realm, block]
132
+ set :auth, (realm == :none ? :none : [realm, block])
53
133
  end
54
134
 
55
135
  # Define the formats that this app implements.
@@ -65,8 +145,20 @@ module Rack
65
145
  # See Rack::API::Formatter::Jsonp for an example on how to create additional
66
146
  # formatters.
67
147
  #
148
+ # Local formats will override the global configuration on that context.
149
+ #
150
+ # Rack::API.app do
151
+ # respond_to :json, :xml, :jsonp
152
+ #
153
+ # version :v1 do
154
+ # respond_to :json
155
+ # end
156
+ # end
157
+ #
158
+ # The code above will accept only <tt>:json</tt> as format on version <tt>:v1</tt>.
159
+ #
68
160
  def respond_to(*formats)
69
- settings[:formats] = formats
161
+ set :formats, formats
70
162
  end
71
163
 
72
164
  # Hold all routes.
@@ -102,15 +194,30 @@ module Rack
102
194
  RUBY
103
195
  end
104
196
 
197
+ private
105
198
  def mount_path(path) # :nodoc:
106
- Rack::Mount::Utils.normalize_path([settings[:prefix], settings[:version], path].join("/"))
199
+ Rack::Mount::Utils.normalize_path([option(:prefix), settings[:version], path].join("/"))
107
200
  end
108
201
 
109
202
  def build_app(block) # :nodoc:
203
+ app = App.new(:block => block)
110
204
  builder = Rack::Builder.new
111
- builder.use Rack::Auth::Basic, settings[:auth][0], &settings[:auth][1] if settings[:auth]
112
- settings[:middlewares].each {|middleware| builder.use(*middleware)}
113
- builder.run App.new(:block => block)
205
+
206
+ # Add middleware for basic authentication.
207
+ auth = option(:auth)
208
+ builder.use Rack::Auth::Basic, auth[0], &auth[1] if auth && auth != :none
209
+
210
+ # Add middleware for format validation.
211
+ builder.use Rack::API::Middleware::Format, option(:formats)
212
+
213
+ # Add middlewares to executation stack.
214
+ option(:middlewares, :merged).each {|middleware| builder.use(*middleware)}
215
+
216
+ # Apply helpers to app.
217
+ helpers = option(:helpers)
218
+ app.extend *helpers unless helpers.empty?
219
+
220
+ builder.run(app)
114
221
  builder.to_app
115
222
  end
116
223
  end
@@ -3,7 +3,7 @@ module Rack
3
3
  module Version
4
4
  MAJOR = 0
5
5
  MINOR = 1
6
- PATCH = 0
6
+ PATCH = 1
7
7
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
8
8
  end
9
9
  end
@@ -3,9 +3,23 @@ require "spec_helper"
3
3
  describe Rack::API, "Basic Authentication" do
4
4
  before do
5
5
  Rack::API.app do
6
+ basic_auth do |user, pass|
7
+ user == "admin" && pass == "test"
8
+ end
9
+
6
10
  version :v1 do
11
+ get("/") { {:success => true} }
12
+ end
13
+
14
+ version :v2 do
15
+ basic_auth :none
16
+ get("/") { {:success => true} }
17
+ get("/credentials") { credentials }
18
+ end
19
+
20
+ version :v3 do
7
21
  basic_auth do |user, pass|
8
- user == "admin" && pass == "test"
22
+ user == "john" && pass == "test"
9
23
  end
10
24
 
11
25
  get("/") { {:success => true} }
@@ -13,18 +27,59 @@ describe Rack::API, "Basic Authentication" do
13
27
  end
14
28
  end
15
29
 
16
- it "denies access" do
17
- get "/v1/"
18
- last_response.status.should == 401
30
+ context "global authorization" do
31
+ it "denies access" do
32
+ get "/v1/"
33
+ last_response.status.should == 401
34
+
35
+ get "/v1/", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "invalid")
36
+ last_response.status.should == 401
37
+
38
+ get "/v1/", {}, "HTTP_AUTHORIZATION" => basic_auth("john", "test")
39
+ last_response.status.should == 401
40
+ end
41
+
42
+ it "grants access" do
43
+ get "/v1/", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "test")
19
44
 
20
- get "/v1/", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "invalid")
21
- last_response.status.should == 401
45
+ last_response.status.should == 200
46
+ JSON.load(last_response.body).should == {"success" => true}
47
+ end
22
48
  end
23
49
 
24
- it "grants access" do
25
- get "/v1/", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "test")
50
+ context "no authorization" do
51
+ it "grants access" do
52
+ get "/v2/"
53
+
54
+ last_response.status.should == 200
55
+ JSON.load(last_response.body).should == {"success" => true}
56
+ end
57
+ end
58
+
59
+ context "local authorization" do
60
+ it "denies access" do
61
+ get "/v3/"
62
+ last_response.status.should == 401
63
+
64
+ get "/v3/", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "test")
65
+ last_response.status.should == 401
66
+ end
67
+
68
+ it "grants access" do
69
+ get "/v3/", {}, "HTTP_AUTHORIZATION" => basic_auth("john", "test")
70
+
71
+ last_response.status.should == 200
72
+ JSON.load(last_response.body).should == {"success" => true}
73
+ end
74
+ end
75
+
76
+ it "returns credentials" do
77
+ get "/v2/credentials", {}, "HTTP_AUTHORIZATION" => basic_auth("admin", "test")
78
+ JSON.load(last_response.body).should == ["admin", "test"]
79
+ end
26
80
 
27
- last_response.status.should == 200
28
- JSON.load(last_response.body).should == {"success" => true}
81
+ it "returns empty array when no credentials are provided" do
82
+ get "/v2/credentials"
83
+ JSON.load(last_response.body).should == []
29
84
  end
30
85
  end
@@ -11,7 +11,7 @@ describe Rack::API, "Format" do
11
11
  end
12
12
  end
13
13
 
14
- it "ignores unknown formats" do
14
+ it "ignores unknown paths/formats" do
15
15
  get "/users.xml"
16
16
  last_response.status.should == 404
17
17
  end
@@ -26,6 +26,16 @@ describe Rack::API, "Format" do
26
26
  end
27
27
  end
28
28
 
29
+ context "invalid format" do
30
+ it "renders 406" do
31
+ get "/v1/users.invalid"
32
+
33
+ last_response.status.should == 406
34
+ last_response.body.should == "Invalid format"
35
+ last_response.headers["Content-Type"].should == "text/plain"
36
+ end
37
+ end
38
+
29
39
  context "JSONP" do
30
40
  it "renders when set through query string" do
31
41
  get "/v1", :format => "jsonp"
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+
3
+ describe Rack::API, "Helpers" do
4
+ before do
5
+ Rack::API.app do
6
+ version :v1 do
7
+ helper Module.new {
8
+ def helper_from_module
9
+ "module"
10
+ end
11
+ }
12
+
13
+ helper do
14
+ def helper_from_block
15
+ "block"
16
+ end
17
+ end
18
+
19
+ get("/") { [helper_from_block, helper_from_module] }
20
+ end
21
+ end
22
+ end
23
+
24
+ it "adds module helper" do
25
+ get "/v1"
26
+ JSON.load(last_response.body).should include("module")
27
+ end
28
+
29
+ it "adds block helper" do
30
+ get "/v1"
31
+ JSON.load(last_response.body).should include("block")
32
+ end
33
+ end
@@ -11,28 +11,23 @@ describe Rack::API::Runner do
11
11
 
12
12
  it "sets available formats" do
13
13
  subject.respond_to(:json, :jsonp, :atom)
14
- subject.settings[:formats].should == [:json, :jsonp, :atom]
14
+ subject.option(:formats).should == [:json, :jsonp, :atom]
15
15
  end
16
16
 
17
17
  it "sets prefix option" do
18
18
  subject.prefix("my/awesome/api")
19
- subject.settings[:prefix].should == "my/awesome/api"
20
- end
21
-
22
- it "considers prefix and version when building paths" do
23
- subject.settings.merge!(:prefix => "api", :version => "v1")
24
- subject.mount_path("users").should == "/api/v1/users"
19
+ subject.option(:prefix).should == "my/awesome/api"
25
20
  end
26
21
 
27
22
  it "stores middleware" do
28
23
  subject.use Rack::Auth::Basic
29
- subject.settings[:middlewares].should == [[Rack::Auth::Basic]]
24
+ subject.option(:middlewares, :merge).should == [[Rack::Auth::Basic]]
30
25
  end
31
26
 
32
27
  it "stores basic auth info" do
33
28
  handler = proc {}
34
29
 
35
30
  subject.basic_auth("Get out!", &handler)
36
- subject.settings[:auth].should == ["Get out!", handler]
31
+ subject.settings[:global][:auth].should == ["Get out!", handler]
37
32
  end
38
33
  end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ describe Rack::API::Runner, "Settings" do
4
+ it "uses global namespace when no version is defined" do
5
+ subject.set :foo, :bar
6
+ subject.settings[:global][:foo].should == :bar
7
+ end
8
+
9
+ it "uses local namespace when version is defined" do
10
+ subject.settings[:version] = "v1"
11
+ subject.set :foo, :bar
12
+
13
+ subject.settings[:foo].should == :bar
14
+ end
15
+
16
+ it "appends item when mode is :append" do
17
+ subject.settings[:global][:list] = []
18
+ subject.set :list, :item, :append
19
+
20
+ subject.settings[:global][:list].should == [:item]
21
+ end
22
+
23
+ it "overrides item when mode is :override" do
24
+ subject.settings[:global][:list] = []
25
+ subject.set :list, [:item], :override
26
+
27
+ subject.settings[:global][:list].should == [:item]
28
+ end
29
+
30
+ it "returns global value" do
31
+ subject.set :name, "John Doe"
32
+ subject.option(:name).should == "John Doe"
33
+ end
34
+
35
+ it "returns local value" do
36
+ subject.settings[:version] = "v1"
37
+ subject.set :name, "John Doe"
38
+
39
+ subject.option(:name).should == "John Doe"
40
+ end
41
+
42
+ it "prefers local setting over global one" do
43
+ subject.set :name, "Mary Doe"
44
+
45
+ subject.settings[:version] = "v1"
46
+ subject.set :name, "John Doe"
47
+
48
+ subject.option(:name).should == "John Doe"
49
+ end
50
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rack-api
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nando Vieira
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-04-07 00:00:00 Z
13
+ date: 2011-04-08 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -96,7 +96,9 @@ files:
96
96
  - Rakefile
97
97
  - examples/basic_auth.rb
98
98
  - examples/custom_class.rb
99
+ - examples/custom_format.rb
99
100
  - examples/custom_headers.rb
101
+ - examples/formats.rb
100
102
  - examples/middleware.rb
101
103
  - examples/multiple_versions.rb
102
104
  - examples/params.rb
@@ -106,6 +108,8 @@ files:
106
108
  - lib/rack/api/formatter.rb
107
109
  - lib/rack/api/formatter/base.rb
108
110
  - lib/rack/api/formatter/jsonp.rb
111
+ - lib/rack/api/middleware.rb
112
+ - lib/rack/api/middleware/format.rb
109
113
  - lib/rack/api/response.rb
110
114
  - lib/rack/api/runner.rb
111
115
  - lib/rack/api/version.rb
@@ -113,12 +117,14 @@ files:
113
117
  - spec/rack-api/basic_auth_spec.rb
114
118
  - spec/rack-api/format_spec.rb
115
119
  - spec/rack-api/headers_spec.rb
120
+ - spec/rack-api/helpers_spec.rb
116
121
  - spec/rack-api/http_methods_spec.rb
117
122
  - spec/rack-api/inheritance_spec.rb
118
123
  - spec/rack-api/middlewares_spec.rb
119
124
  - spec/rack-api/params_spec.rb
120
125
  - spec/rack-api/paths_spec.rb
121
126
  - spec/rack-api/runner_spec.rb
127
+ - spec/rack-api/settings_spec.rb
122
128
  - spec/rack-api/short_circuit_spec.rb
123
129
  - spec/spec_helper.rb
124
130
  - spec/support/awesome_middleware.rb
@@ -156,12 +162,14 @@ test_files:
156
162
  - spec/rack-api/basic_auth_spec.rb
157
163
  - spec/rack-api/format_spec.rb
158
164
  - spec/rack-api/headers_spec.rb
165
+ - spec/rack-api/helpers_spec.rb
159
166
  - spec/rack-api/http_methods_spec.rb
160
167
  - spec/rack-api/inheritance_spec.rb
161
168
  - spec/rack-api/middlewares_spec.rb
162
169
  - spec/rack-api/params_spec.rb
163
170
  - spec/rack-api/paths_spec.rb
164
171
  - spec/rack-api/runner_spec.rb
172
+ - spec/rack-api/settings_spec.rb
165
173
  - spec/rack-api/short_circuit_spec.rb
166
174
  - spec/spec_helper.rb
167
175
  - spec/support/awesome_middleware.rb