Skip to content

Commit 0fe17a5

Browse files
author
Michael Bleigh
committed
Beginnings of formatter middleware.
1 parent f9c9cf3 commit 0fe17a5

File tree

10 files changed

+124
-3
lines changed

10 files changed

+124
-3
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,7 @@ tmtags
1717
coverage
1818
rdoc
1919
pkg
20+
.rvmrc
21+
.bundle
2022

2123
## PROJECT::SPECIFIC

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ gem 'rack'
22
gem 'rack-mount'
33
gem 'rack-jsonp'
44

5+
gem 'json'
6+
gem 'multi_json'
7+
58
group :test do
69
gem 'rspec', '>= 2.0.0.beta.19'
710
gem 'rack-test'

Gemfile.lock

+4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ GEM
1010
diff-lcs (1.1.2)
1111
gherkin (2.1.5)
1212
trollop (~> 1.16.2)
13+
json (1.4.3)
1314
json_pure (1.4.3)
15+
multi_json (0.0.4)
1416
rack (1.2.1)
1517
rack-jsonp (1.0.0)
1618
rack-mount (0.6.9)
@@ -33,6 +35,8 @@ PLATFORMS
3335

3436
DEPENDENCIES
3537
cucumber (>= 0.8.5)
38+
json
39+
multi_json
3640
rack
3741
rack-jsonp
3842
rack-mount

Rakefile

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ begin
1010
gem.email = "michael@intridea.com"
1111
gem.homepage = "http://github.com/intridea/grape"
1212
gem.authors = ["Michael Bleigh"]
13+
gem.add_dependency 'rack'
14+
gem.add_dependency 'multi_json'
1315
gem.add_development_dependency "rspec", ">= 1.2.9"
1416
gem.add_development_dependency "cucumber", ">= 0"
1517
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings

lib/grape.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33

44
require 'grape/middleware/base'
55
require 'grape/middleware/prefixer'
6-
require 'grape/middleware/versioner'
6+
require 'grape/middleware/versioner'
7+
require 'grape/middleware/formatter'

lib/grape/middleware/error.rb

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require 'grape/middleware/base'
2+
3+
module Grape
4+
module Middleware
5+
class Error < Base
6+
7+
end
8+
end
9+
end

lib/grape/middleware/formatter.rb

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
require 'grape/middleware/base'
2+
require 'multi_json'
3+
4+
module Grape
5+
module Middleware
6+
class Formatter < Base
7+
CONTENT_TYPES = {
8+
:xml => 'application/xml',
9+
:json => 'application/json',
10+
:atom => 'application/atom+xml',
11+
:rss => 'application/rss+xml'
12+
}
13+
14+
def default_options
15+
{
16+
:default_format => :json,
17+
:content_types => {}
18+
}
19+
end
20+
21+
def content_types
22+
CONTENT_TYPES.merge(options[:content_types])
23+
end
24+
25+
def before
26+
fmt = format_from_extension || format_from_header || options[:default_format]
27+
28+
if content_types.key?(fmt)
29+
env['api.format'] = fmt
30+
else
31+
env['api.error.status'] = 406
32+
env['api.error.message'] = 'The requested format is not supported.'
33+
end
34+
end
35+
36+
def format_from_extension
37+
parts = request.path.split('.')
38+
hit = parts.last.to_sym
39+
40+
if parts.size <= 1
41+
nil
42+
else
43+
hit
44+
end
45+
end
46+
47+
def format_from_header
48+
# TODO: Implement Accept header parsing.
49+
end
50+
51+
def after
52+
status, headers, bodies = *@app_response
53+
bodies.map! do |body|
54+
MultiJson.encode(body)
55+
end
56+
[status, headers, bodies]
57+
end
58+
end
59+
end
60+
end

spec/grape/middleware/error_spec.rb

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
require 'spec_helper'
2+
3+
describe Grape::Middleware::Error do
4+
5+
end
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require 'spec_helper'
2+
3+
describe Grape::Middleware::Formatter do
4+
subject{ Grape::Middleware::Formatter.new(app)}
5+
before{ subject.stub!(:dup).and_return(subject) }
6+
7+
let(:app){ lambda{|env| [200, {}, [@body]]} }
8+
9+
context 'serialization' do
10+
it 'should look at the bodies for possibly serializable data' do
11+
@body = {"abc" => "def"}
12+
status, headers, bodies = *subject.call({'PATH_INFO' => '/somewhere'})
13+
bodies.first.should == MultiJson.encode(@body)
14+
end
15+
end
16+
17+
context 'detection' do
18+
it 'should use the extension if one is provided' do
19+
subject.call({'PATH_INFO' => '/info.xml'})
20+
subject.env['api.format'].should == :xml
21+
subject.call({'PATH_INFO' => '/info.json'})
22+
subject.env['api.format'].should == :json
23+
end
24+
25+
it 'should use the default format if none is provided' do
26+
subject.call({'PATH_INFO' => '/info'})
27+
subject.env['api.format'].should == :json
28+
end
29+
30+
it 'should throw an error on an unrecognized format' do
31+
subject.call({'PATH_INFO' => '/info.barklar'})
32+
subject.env['api.error.status'].should == 406
33+
end
34+
end
35+
end

spec/spec_helper.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
require 'rubygems'
77
require 'bundler'
8-
Bundler.setup :test
8+
Bundler.setup :default, :test
99

1010
require 'rspec'
1111
require 'rack/test'
1212

1313
RSpec.configure do |config|
14-
14+
config.include Rack::Test::Methods
1515
end

0 commit comments

Comments
 (0)