From 4d0140641e47686044adbb283796e07308ac2d6f Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 9 Jul 2012 16:27:38 -0400 Subject: [PATCH] Implements #97: allow overriding Content-Type. --- CHANGELOG.markdown | 1 + README.markdown | 27 +++++++++++++++++++-------- lib/grape/endpoint.rb | 11 ++++++++--- lib/grape/middleware/formatter.rb | 2 +- spec/grape/api_spec.rb | 12 ++++++++++-- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 2a9a9e2265..484b35a084 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -11,6 +11,7 @@ Next Release * [#159](https://github.com/intridea/grape/pull/159): Added `:requirements` to routes, allowing to use reserved characters in paths - [@gaiottino](https://github.com/gaiottino). * [#156](https://github.com/intridea/grape/pull/156): Added support for adding formatters to entities - [@bobbytables](https://github.com/bobbytables). * [#183](https://github.com/intridea/grape/pull/183): Added ability to include documentation in entities - [@flah00](https://github.com/flah00). +* [#97](https://github.com/intridea/grape/issues/97): Allow overriding `Content-Type` - [@dblock](https://github.com/dblock). 0.2.0 (3/28/2012) ================= diff --git a/README.markdown b/README.markdown index c7ea07f29b..a861aef75f 100644 --- a/README.markdown +++ b/README.markdown @@ -88,7 +88,7 @@ end ## Mounting -The above sample creates a Rack application that can be run from a rackup *config.ru* file +The above sample creates a Rack application that can be run from a rackup *config.ru* file with `rackup`: ``` ruby @@ -128,7 +128,7 @@ There are three strategies in which clients can reach your API's endpoints: `:he version 'v1', :using => :header ``` -Using this versioning strategy, clients should pass the desired version in the HTTP Accept head. +Using this versioning strategy, clients should pass the desired version in the HTTP Accept head. curl -H Accept=application/vnd.twitter-v1+json http://localhost:9292/statuses/public_timeline @@ -147,7 +147,7 @@ Using this versioning strategy, clients should pass the desired version in the U curl -H http://localhost:9292/v1/statuses/public_timeline -Serialization takes place automatically. +Serialization takes place automatically. ### Param @@ -155,7 +155,7 @@ Serialization takes place automatically. version 'v1', :using => :param ``` -Using this versioning strategy, clients should pass the desired version as a request parameter, either in the URL query string or in the request body. +Using this versioning strategy, clients should pass the desired version as a request parameter, either in the URL query string or in the request body. curl -H http://localhost:9292/events?apiver=v1 @@ -169,7 +169,7 @@ version 'v1', :using => :param, :parameter => "v" ## Parameters -Parameters are available through the `params` hash object. This includes `GET` and `POST` parameters, +Parameters are available through the `params` hash object. This includes `GET` and `POST` parameters, along with any named parameters you specify in your route strings. ```ruby @@ -426,9 +426,20 @@ class Twitter::API < Grape::API end ``` +You can override the content-type by setting the `Content-Type` header. + +``` ruby +class API < Grape::API + get '/script' do + content_type "application/javascript" + "var x = 1;" + end +end +``` + ## Writing Tests -You can test a Grape API with RSpec by making HTTP requests and examining the response. +You can test a Grape API with RSpec by making HTTP requests and examining the response. ### Writing Tests with Rack @@ -579,7 +590,7 @@ end ### Caveats Entities with duplicate exposure names and conditions will silently overwrite one another. -In the following example, when object#check equals "foo", only afield will be exposed. +In the following example, when object#check equals "foo", only afield will be exposed. However, when object#check equals "bar" both bfield and foo will be exposed. ```ruby @@ -611,7 +622,7 @@ end Grape lets you add a description to an API along with any other optional elements that can also be inspected at runtime. -This can be useful for generating documentation. If the response +This can be useful for generating documentation. If the response requires documentation, consider using an entity. ``` ruby diff --git a/lib/grape/endpoint.rb b/lib/grape/endpoint.rb index 3ec4ad3eb0..0aa35edaa8 100644 --- a/lib/grape/endpoint.rb +++ b/lib/grape/endpoint.rb @@ -152,7 +152,7 @@ def error!(message, status=403) end # Redirect to a new url. - # + # # @param url [String] The url to be redirect. # @param options [Hash] The options used when redirect. # :permanent, default true. @@ -163,7 +163,7 @@ def redirect(url, options = {}) else if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase != "GET" status 303 - else + else status 302 end end @@ -197,7 +197,12 @@ def header(key = nil, val = nil) @header end end - + + # Set response content-type + def content_type(val) + header('Content-Type', val) + end + # Set or get a cookie # # @example diff --git a/lib/grape/middleware/formatter.rb b/lib/grape/middleware/formatter.rb index 7b429cdf9f..03aeda1661 100644 --- a/lib/grape/middleware/formatter.rb +++ b/lib/grape/middleware/formatter.rb @@ -73,7 +73,7 @@ def after bodymap = bodies.collect do |body| formatter.call(body) end - headers['Content-Type'] = content_types[env['api.format']] + headers['Content-Type'] = content_types[env['api.format']] unless headers['Content-Type'] Rack::Response.new(bodymap, status, headers).to_a end end diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 4d654082cd..723caea0cb 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -731,12 +731,20 @@ def three describe ".content_type" do it "sets additional content-type" do subject.content_type :xls, "application/vnd.ms-excel" - subject.get(:hello) do + subject.get :excel do "some binary content" end - get '/hello.xls' + get '/excel.xls' last_response.content_type.should == "application/vnd.ms-excel" end + it "allows to override content-type" do + subject.get :content do + content_type "text/javascript" + "var x = 1;" + end + get '/content' + last_response.content_type.should == "text/javascript" + end end describe ".default_error_status" do