Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
This is a simple Rack Middleware to set the request content type for specific routes. It checks if a content type is set and does not override the existing one. The options allow you to specify the request methods, path (with a string or a regular expression) and the content type to be set.
module Rack
class ApiContentType
def initialize(app, methods = [:post, :patch], path = /^\/api\/v2+/, content_type = 'application/json')
@app = app
@methods = (methods.is_a?(Array) ? methods : [methods]).map{ |item| item.to_s.upcase }
@path = path
@content_type = content_type
end
def call(env)
req = Rack::Request.new(env)
if match_path?(req.path) and match_method?(req.request_method)
env['CONTENT_TYPE'] = @content_type if req.content_type.nil? or req.content_type.empty?
end
@app.call(env)
end
private
def match_path?(path)
@path.is_a?(Regexp) ? @path.match(path.to_s) : @path == path.to_s
end
def match_method?(method)
@methods.empty? || @methods.include?(method)
end
end
end
require 'spec_helper'
describe Rack::ApiContentType do
App = lambda { |env| [200, {'Content-Type' => 'text/plain'}, env['PATH_INFO']] }
context '/' do
it 'does not set the content type on default requests' do
request = Rack::MockRequest.env_for("/")
request['CONTENT_TYPE'] = 'text/plain'
response = Rack::ApiContentType.new(App).call(request)
request['CONTENT_TYPE'].should == 'text/plain'
end
end
context '/api/v2' do
it 'does set the content type' do
request = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
response = Rack::ApiContentType.new(App).call(request)
request['CONTENT_TYPE'].should == 'application/json'
end
it 'does not override existing content type' do
request = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request['CONTENT_TYPE'] = 'application/xml'
response = Rack::ApiContentType.new(App).call(request)
request['CONTENT_TYPE'].should == 'application/xml'
end
it 'does override empty content type' do
request = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request['CONTENT_TYPE'] = ''
response = Rack::ApiContentType.new(App).call(request)
request['CONTENT_TYPE'].should == 'application/json'
end
end
context 'method' do
it 'allows to specify the methods' do
request1 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request2 = Rack::MockRequest.env_for("/api/v2/customers/1", method: :patch)
response1 = Rack::ApiContentType.new(App, :post).call(request1)
response2 = Rack::ApiContentType.new(App, :post).call(request2)
request1['CONTENT_TYPE'].should == 'application/json'
request2['CONTENT_TYPE'].should_not == 'application/json'
end
it 'may be an array' do
request1 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request2 = Rack::MockRequest.env_for("/api/v2/customers/1", method: :patch)
response1 = Rack::ApiContentType.new(App, [:post, :patch]).call(request1)
response2 = Rack::ApiContentType.new(App, [:post, :patch]).call(request2)
request1['CONTENT_TYPE'].should == 'application/json'
request2['CONTENT_TYPE'].should == 'application/json'
end
end
context 'path' do
it 'allows to specify the path' do
request1 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request2 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
response1 = Rack::ApiContentType.new(App, :post, '/api/v2/customers').call(request1)
response2 = Rack::ApiContentType.new(App, :post, '/api/v2/cases').call(request2)
request1['CONTENT_TYPE'].should == 'application/json'
request2['CONTENT_TYPE'].should_not == 'application/json'
end
it 'may be a regular expression' do
request1 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
request2 = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
response1 = Rack::ApiContentType.new(App, :post, '/api/v2/customers').call(request1)
response2 = Rack::ApiContentType.new(App, :post, /^\/api\/v2+/).call(request2)
request1['CONTENT_TYPE'].should == 'application/json'
request2['CONTENT_TYPE'].should == 'application/json'
end
end
context 'content type' do
it 'allows to specify the content type' do
request = Rack::MockRequest.env_for("/api/v2/customers", method: :post)
response = Rack::ApiContentType.new(App, :post, '/api/v2/customers', 'application/xml').call(request)
request['CONTENT_TYPE'].should == 'application/xml'
end
end
end
ENV['RACK_ENV'] = 'test'
require 'rspec'
require 'rack/test'
require 'simplecov'
SimpleCov.start
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rack/api_content_type'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.