hyperdrive 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +12 -4
  3. data/Gemfile +2 -0
  4. data/hyperdrive.gemspec +6 -2
  5. data/lib/hyperdrive/docs.rb +10 -11
  6. data/lib/hyperdrive/dsl/resource.rb +10 -15
  7. data/lib/hyperdrive/dsl.rb +49 -3
  8. data/lib/hyperdrive/endpoint.rb +65 -0
  9. data/lib/hyperdrive/errors/missing_required_param.rb +19 -0
  10. data/lib/hyperdrive/errors/not_acceptable.rb +18 -0
  11. data/lib/hyperdrive/errors.rb +13 -8
  12. data/lib/hyperdrive/filter.rb +20 -0
  13. data/lib/hyperdrive/hateoas.rb +45 -0
  14. data/lib/hyperdrive/middleware/accept.rb +16 -0
  15. data/lib/hyperdrive/middleware/content_negotiation.rb +19 -0
  16. data/lib/hyperdrive/middleware/cors.rb +36 -0
  17. data/lib/hyperdrive/middleware/error.rb +35 -0
  18. data/lib/hyperdrive/middleware/request_method.rb +31 -0
  19. data/lib/hyperdrive/middleware/required_params.rb +35 -0
  20. data/lib/hyperdrive/middleware/resource.rb +18 -0
  21. data/lib/hyperdrive/middleware/sanitize_params.rb +25 -0
  22. data/lib/hyperdrive/middleware.rb +10 -0
  23. data/lib/hyperdrive/param.rb +44 -0
  24. data/lib/hyperdrive/resource.rb +74 -30
  25. data/lib/hyperdrive/server.rb +16 -17
  26. data/lib/hyperdrive/utils.rb +27 -0
  27. data/lib/hyperdrive/values.rb +37 -3
  28. data/lib/hyperdrive/version.rb +1 -1
  29. data/lib/hyperdrive.rb +21 -7
  30. data/spec/hyperdrive/docs_spec.rb +14 -8
  31. data/spec/hyperdrive/dsl/resource_spec.rb +27 -37
  32. data/spec/hyperdrive/dsl_spec.rb +52 -0
  33. data/spec/hyperdrive/endpoint_spec.rb +22 -0
  34. data/spec/hyperdrive/filter_spec.rb +34 -0
  35. data/spec/hyperdrive/hateoas_spec.rb +42 -0
  36. data/spec/hyperdrive/middleware/accept_spec.rb +15 -0
  37. data/spec/hyperdrive/middleware/content_negotiation_spec.rb +29 -0
  38. data/spec/hyperdrive/middleware/cors_spec.rb +47 -0
  39. data/spec/hyperdrive/middleware/error_spec.rb +25 -0
  40. data/spec/hyperdrive/middleware/request_method_spec.rb +28 -0
  41. data/spec/hyperdrive/middleware/required_params_spec.rb +43 -0
  42. data/spec/hyperdrive/middleware/resource_spec.rb +15 -0
  43. data/spec/hyperdrive/middleware/sanitize_params_spec.rb +24 -0
  44. data/spec/hyperdrive/param_spec.rb +34 -0
  45. data/spec/hyperdrive/resource_spec.rb +87 -25
  46. data/spec/hyperdrive/server_spec.rb +48 -7
  47. data/spec/hyperdrive/utils_spec.rb +38 -0
  48. data/spec/hyperdrive/values_spec.rb +37 -0
  49. data/spec/spec_helper.rb +71 -12
  50. metadata +106 -11
  51. data/.coveralls.yml +0 -1
  52. data/lib/hyperdrive/dsl/main.rb +0 -19
  53. data/lib/hyperdrive/response.rb +0 -42
  54. data/spec/hyperdrive/dsl/main_spec.rb +0 -16
  55. data/spec/hyperdrive/response_spec.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 26dee10778c01ac284135a3aeac9a9f33af6741c
4
- data.tar.gz: f6e4adf3982bef03df48d8fdc333b09fead28833
3
+ metadata.gz: 898b32e10dc9b2836f112818125fcb5a07f28ce0
4
+ data.tar.gz: 917e3c1f3f9ba879170bbbaefc216593de6e2288
5
5
  SHA512:
6
- metadata.gz: bc67ee73c8f6866e8200bfd861a857a61b95dbb4f5573b361471b6bb7130dce6b04e622a996cf75ff3e047ea98359682922ea21374ab3cf136db49e978f07ae9
7
- data.tar.gz: eb7e54a97ebd50a00ca77c748bd027987c3f883e5cd9f5c8759bae37f0478cd0bb0e5c01eade331f02261b6019d7dde4b8169235e82f89e98aba46e3059a5311
6
+ metadata.gz: 055bf9088099afc3dadb018b7042a44a2589a52d91117e7c7e70eeeaf1e4fc16642980d6a5500a84fd3cffac9511c164f6ed3c51687469cdc24dfbc57b5986ad
7
+ data.tar.gz: 6dd19b1ddbd02b84a400ddd3aa22a952a7b06172e6164badd1de7a03b8b3037fb2f66ec90c9c206277c7dda561f89108739e3ab273f0f11bc9285f7c77b23a81
data/.travis.yml CHANGED
@@ -1,6 +1,14 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.0
4
- - 1.9.3
5
- - jruby-head
6
- - rbx-2.1.1
3
+ - 2.1.1
4
+ - 1.9.3
5
+ - jruby-head
6
+ - rbx-2.1.1
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: jruby-head
10
+ - rvm: rbx-2.1.1
11
+ env:
12
+ global:
13
+ secure: Tl3oBsBZRI5bMrtNH5mtTDvSTlTxNbsKaAnQ7KQ2KMyiH/eHolOSIbUYB9NB3GRMC6XSyFShRCaYPA/ET36HI+Jw3PFT/XADdiOdFqlk6VyJEUPznNQ1nlp8AsyNn+IexZXIl8DdqmZxGHlY6YKDbQV/U1v+FeW8X5j3TLN1mcw=
14
+ before_install: gem install bundler
data/Gemfile CHANGED
@@ -19,4 +19,6 @@ group :test do
19
19
  gem 'minitest-spec-context', require: false
20
20
  gem 'minitest-reporters', require: false
21
21
  gem 'rack-test', require: false
22
+ gem 'rubinius-coverage', require: false, platforms: :rbx
23
+ gem 'codeclimate-test-reporter', require: false
22
24
  end
data/hyperdrive.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.authors = ['StyleSeek Engineering']
10
10
  gem.email = ['engineering@styleseek.com']
11
11
  gem.summary = %q{Hypermedia State Machine}
12
- gem.description = %q{Ruby DSL for defining self-documenting, HATEOAS™ complaint, Hypermedia API endpoints.}
12
+ gem.description = %q{Ruby DSL for defining self-documenting, HATEOAS™ compliant, Hypermedia API endpoints.}
13
13
  gem.homepage = "https://github.com/styleseek/hyperdrive"
14
14
  gem.license = "MIT"
15
15
 
@@ -18,7 +18,11 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.add_dependency 'rack'
22
21
  gem.add_dependency 'linguistics'
22
+ gem.add_dependency 'oj'
23
+ gem.add_dependency 'rack'
24
+ gem.add_dependency 'rack-cache'
25
+ gem.add_dependency 'rack-ssl'
26
+ gem.add_dependency 'rack-accept'
23
27
  gem.add_dependency 'thor'
24
28
  end
@@ -12,13 +12,13 @@ module Hyperdrive
12
12
  out = ""
13
13
  resources.each_value do |resource|
14
14
  out += header(resource.name)
15
- out += paragraph(resource.desc)
15
+ out += paragraph(resource.description)
16
16
  out += header("Endpoint URL", 2)
17
17
  out += paragraph(bullet(code(resource.endpoint), 1))
18
18
  out += header("Params", 2)
19
- out += list(resource.allowed_params)
19
+ out += list(resource.params.map { |_,param| param.to_hash })
20
20
  out += header("Filters", 2)
21
- out += list(resource.filters)
21
+ out += list(resource.filters.map { |_,filter| filter.to_hash })
22
22
  end
23
23
  out
24
24
  end
@@ -53,16 +53,15 @@ module Hyperdrive
53
53
 
54
54
  def list(items)
55
55
  list = ""
56
- items.each do |key, value|
57
- list += bullet(bold(key), 1)
56
+ items.each do |item|
57
+ list += bullet(bold(item[:name]), 1)
58
+ item.each do |key, value|
59
+ list += bullet(italics(key), 2)
58
60
 
59
- value.each do |subkey, subvalue|
60
- list += bullet(italics(subkey), 2)
61
-
62
- if subvalue.kind_of? Array
63
- list += bullet(code_options(subvalue), 3)
61
+ if value.kind_of? Array
62
+ list += bullet(code_options(value), 3)
64
63
  else
65
- list += bullet(subvalue, 3)
64
+ list += bullet(value, 3)
66
65
  end
67
66
  end
68
67
  end
@@ -3,18 +3,19 @@
3
3
  module Hyperdrive
4
4
  module DSL
5
5
  class Resource
6
+ include Values
6
7
  attr_reader :resource
7
- def initialize(key, &block)
8
- @resource = ::Hyperdrive::Resource.new(key)
9
- instance_eval(&block) if block_given?
8
+ def initialize(name, hyperdrive_config)
9
+ @resource = ::Hyperdrive::Resource.new(name, hyperdrive_config)
10
+ instance_eval(&Proc.new) if block_given?
10
11
  end
11
12
 
12
13
  def name(name)
13
14
  resource.name = name
14
15
  end
15
16
 
16
- def desc(description)
17
- resource.desc = description
17
+ def description(description)
18
+ resource.description = description
18
19
  end
19
20
 
20
21
  def param(*args)
@@ -25,17 +26,11 @@ module Hyperdrive
25
26
  resource.register_filter(*args)
26
27
  end
27
28
 
28
- def request(method, &block)
29
- unless definable_request_methods.include? method
30
- raise Errors::DSL::UnknownArgument.new(method, 'request')
29
+ def request(request_method)
30
+ unless definable_request_methods.include? request_method
31
+ raise Errors::DSL::UnknownArgument.new(request_method, 'request')
31
32
  end
32
- resource.define_request_handler(method, block)
33
- end
34
-
35
- private
36
-
37
- def definable_request_methods
38
- [:get, :post, :put, :patch, :delete].freeze
33
+ resource.register_request_handler(request_method, Proc.new)
39
34
  end
40
35
  end
41
36
  end
@@ -1,9 +1,55 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'hyperdrive/dsl/main'
4
3
  require 'hyperdrive/dsl/resource'
5
4
 
5
+ module Hyperdrive
6
+ module DSL
7
+ include Values
8
+ extend self
9
+ attr_reader :config, :resources
10
+
11
+ def instance
12
+ @config ||= default_config.dup
13
+ @resources ||= {}
14
+ self
15
+ end
16
+
17
+ private
18
+
19
+ def name(name)
20
+ @config[:name] = name
21
+ end
22
+
23
+ def description(description)
24
+ @config[:description] = description
25
+ end
26
+
27
+ def vendor(vendor)
28
+ @config[:vendor] = vendor
29
+ end
30
+
31
+ def media_types(media_types)
32
+ @config[:media_types] = media_types
33
+ end
34
+
35
+ def cors(options = {})
36
+ allowed_options = default_cors_options.keys
37
+ options = Utils.sanitize_keys(allowed_options, options)
38
+ @config[:cors] = config[:cors].merge(options)
39
+ end
40
+
41
+ def resource(name)
42
+ @resources[name] = Resource.new(name, @config, &Proc.new).resource
43
+ end
44
+
45
+ def reset! # not terribly useful outside of a test environment :(
46
+ @config = default_config.dup
47
+ @resources = {}
48
+ end
49
+ end
50
+ end
51
+
6
52
  def hyperdrive(&block)
7
- Hyperdrive::DSL::Main.instance.instance_eval(&block) if block_given?
8
- Hyperdrive::DSL::Main.instance
53
+ Hyperdrive::DSL.instance.instance_eval(&block) if block_given?
54
+ Hyperdrive::DSL.instance
9
55
  end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ class Endpoint
5
+
6
+ def self.call(env)
7
+ @env = env
8
+ @request = Rack::Request.new(@env)
9
+ @media_type = env['hyperdrive.media_type']
10
+ @params = env['hyperdrive.params']
11
+ @resource = env['hyperdrive.resource']
12
+ @headers = Hyperdrive::Values.default_headers.dup
13
+ @headers.merge!('Allow' => resource.allowed_methods, 'Content-Type' => @media_type)
14
+
15
+ response.finish
16
+ end
17
+
18
+ private
19
+
20
+ class << self
21
+ attr_reader :env, :request, :media_type, :params, :resource
22
+ attr_accessor :headers
23
+ end
24
+
25
+ def self.json?
26
+ media_type =~ /json$/
27
+ end
28
+
29
+ def self.xml?
30
+ media_type =~ /xml$/
31
+ end
32
+
33
+ def self.render(body)
34
+ case body
35
+ when Array, Hash
36
+ Oj.dump(body, mode: :compat) if json?
37
+ when String
38
+ body
39
+ else
40
+ body.to_s
41
+ end
42
+ end
43
+
44
+ def self.status
45
+ case env['REQUEST_METHOD']
46
+ when 'POST'
47
+ 201
48
+ when 'DELETE'
49
+ 204
50
+ else
51
+ 200
52
+ end
53
+ end
54
+
55
+ def self.body
56
+ body = instance_eval(&resource.request_handler(env['REQUEST_METHOD']))
57
+ body = '' if env['REQUEST_METHOD'] == 'DELETE'
58
+ body
59
+ end
60
+
61
+ def self.response
62
+ ::Rack::Response.new(body, status, headers)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,19 @@
1
+ module Hyperdrive
2
+ module Errors
3
+ class MissingRequiredParam < HTTPError
4
+ attr_reader :param, :http_request_method
5
+ def initialize(param, http_request_method)
6
+ @param = param
7
+ @http_request_method = http_request_method
8
+ end
9
+
10
+ def message
11
+ "The #{param} param is required by #{http_request_method} requests."
12
+ end
13
+
14
+ def http_status_code
15
+ 400
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module Hyperdrive
2
+ module Errors
3
+ class NotAcceptable < HTTPError
4
+ def initialize(http_accept)
5
+ @http_accept = http_accept
6
+ end
7
+
8
+ def message
9
+ "This resource is not capable of generating content in the format requested by the Accept headers (#{@http_accept})."
10
+ end
11
+
12
+ def http_status_code
13
+ 406
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -1,10 +1,15 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'hyperdrive/errors/http_error'
4
- require 'hyperdrive/errors/bad_request'
5
- require 'hyperdrive/errors/internal_server_error'
6
- require 'hyperdrive/errors/method_not_allowed'
7
- require 'hyperdrive/errors/not_found'
8
- require 'hyperdrive/errors/not_implemented'
9
- require 'hyperdrive/errors/unauthorized'
10
- require 'hyperdrive/errors/dsl/unknown_argument'
3
+ # DSL Errors
4
+ require 'hyperdrive/errors/dsl/unknown_argument'
5
+
6
+ # HTTP Errors
7
+ require 'hyperdrive/errors/http_error' # 500 (Catch All)
8
+ require 'hyperdrive/errors/bad_request' # 400 (Generic)
9
+ require 'hyperdrive/errors/internal_server_error' # 500 (Generic)
10
+ require 'hyperdrive/errors/method_not_allowed' # 405
11
+ require 'hyperdrive/errors/missing_required_param' # 400 (Specific)
12
+ require 'hyperdrive/errors/not_acceptable' # 406
13
+ require 'hyperdrive/errors/not_found' # 404
14
+ require 'hyperdrive/errors/not_implemented' # 501
15
+ require 'hyperdrive/errors/unauthorized' # 401
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ class Filter < Param
5
+ def initialize(name, description, options = {})
6
+ @name = name.to_s
7
+ @description = description
8
+ options = default_options.merge(options)
9
+ @required = if options[:required] == true
10
+ %w(GET HEAD)
11
+ elsif options[:required] == false
12
+ []
13
+ else
14
+ Array(options[:required])
15
+ end
16
+ @type = options[:type]
17
+ @constraints = "#{required_constraint} #{options[:constraints]}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ class HATEOAS
5
+ extend Hyperdrive::Values
6
+
7
+ def self.call(env)
8
+ if hyperdrive.resources.empty? || env['PATH_INFO'] != '/'
9
+ raise Hyperdrive::Errors::NotFound
10
+ end
11
+
12
+ endpoints = hyperdrive.resources.map do |_,resource|
13
+ resource.to_hash
14
+ end
15
+
16
+ api = {
17
+ _links: { self: { href: '/' } },
18
+ name: hyperdrive.config[:name],
19
+ description: hyperdrive.config[:description],
20
+ vendor: hyperdrive.config[:vendor],
21
+ resources: endpoints
22
+ }
23
+
24
+ media_types = %w(hal+json json).map do |media_type|
25
+ "application/vnd.#{hyperdrive.config[:vendor]}+#{media_type}"
26
+ end
27
+
28
+ media_types += %w(application/hal+json application/json)
29
+ content_type = env['hyperdrive.accept'].best_of(media_types)
30
+ body = if content_type =~ /json$/
31
+ Oj.dump(api, mode: :compat)
32
+ else
33
+ raise Hyperdrive::Errors::NotAcceptable.new(env['HTTP_ACCEPT'])
34
+ end
35
+
36
+ status = 200
37
+ headers = {}
38
+ headers['Access-Control-Allow-Origin'] = '*'
39
+ headers['Access-Control-Allow-Methods'] = 'GET, HEAD, OPTIONS'
40
+ headers['Allow'] = 'GET, HEAD, OPTIONS'
41
+ headers['Content-Type'] = content_type
42
+ [status, headers, [body]]
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class Accept
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ env['hyperdrive.accept'] = Rack::Accept::MediaType.new(env['HTTP_ACCEPT'])
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class ContentNegotiation
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ accept = env['hyperdrive.accept']
12
+ acceptable_content_types = env['hyperdrive.resource'].acceptable_content_types(env['REQUEST_METHOD'])
13
+ env['hyperdrive.media_type'] = accept.best_of(acceptable_content_types)
14
+ raise Hyperdrive::Errors::NotAcceptable.new(env['HTTP_ACCEPT']) unless env['hyperdrive.media_type']
15
+ @app.call(env)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class CORS
6
+ def initialize(app, options = {})
7
+ @app = app
8
+ @options = options
9
+ end
10
+
11
+ def call(env)
12
+ status, headers, body = @app.call(env)
13
+ allowed_methods = '*'
14
+ unless env['hyperdrive.resource'].nil?
15
+ allowed_methods = env['hyperdrive.resource'].allowed_methods
16
+ end
17
+ cors = cors_headers(allowed_methods)
18
+ headers.merge!(cors)
19
+ [status, headers, body]
20
+ end
21
+
22
+ private
23
+
24
+ def cors_headers(allowed_methods = '*')
25
+ {
26
+ 'Access-Control-Allow-Origin' => Array(@options[:origins]).join(", "),
27
+ 'Access-Control-Allow-Methods' => Array(allowed_methods).join(", "),
28
+ 'Access-Control-Allow-Headers' => Array(@options[:allow_headers]).join(", "),
29
+ 'Access-Control-Allow-Credentials' => (@options[:credentials] || false).to_s,
30
+ 'Access-Control-Max-Age' => @options[:max_age].to_i.to_s,
31
+ 'Access-Control-Expose-Headers' => Array(@options[:expose_headers]).join(", ")
32
+ }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class Error
6
+ include Hyperdrive::Values
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(env)
13
+ @app.call(env)
14
+ rescue Hyperdrive::Errors::HTTPError => e
15
+ status = e.http_status_code
16
+ headers = { 'Content-Type' => 'application/json',
17
+ 'Allow' => supported_request_methods.join(', ') }
18
+ body = Oj.dump(error_message(e), mode: :compat)
19
+ [status, headers, [body]]
20
+ end
21
+
22
+ private
23
+
24
+ def error_message(e)
25
+ {
26
+ _links: { root: { href: '/', title: 'API Root' } },
27
+ error: {
28
+ type: "#{e.class.to_s.split('::').last}",
29
+ message: e.message
30
+ }
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class RequestMethod
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ http_request_method = env['REQUEST_METHOD']
12
+
13
+ unless request_method_supported?(http_request_method)
14
+ raise Hyperdrive::Errors::NotImplemented.new(http_request_method)
15
+ end
16
+
17
+ unless env['hyperdrive.resource'].request_method_allowed?(http_request_method)
18
+ raise Hyperdrive::Errors::MethodNotAllowed.new(http_request_method)
19
+ end
20
+
21
+ @app.call(env)
22
+ end
23
+
24
+ private
25
+
26
+ def request_method_supported?(http_request_method)
27
+ Hyperdrive::Values.http_request_methods.key?(http_request_method)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class RequiredParams
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ @env = env
12
+ if %w(GET HEAD).include? env['REQUEST_METHOD']
13
+ check_required_params(env['hyperdrive.resource'].filters)
14
+ elsif %W(POST PUT PATCH DELETE).include? env['REQUEST_METHOD']
15
+ check_required_params(env['hyperdrive.resource'].params)
16
+ end
17
+ @app.call(env)
18
+ end
19
+
20
+ def check_required_params(params)
21
+ params.each do |param, options|
22
+ if @env['hyperdrive.resource'].required?(param, @env['REQUEST_METHOD'])
23
+ if @env['hyperdrive.params'].key?(param)
24
+ if @env['hyperdrive.params'][param] == ''
25
+ raise Errors::MissingRequiredParam.new(param, @env['REQUEST_METHOD'])
26
+ end
27
+ else
28
+ raise Errors::MissingRequiredParam.new(param, @env['REQUEST_METHOD'])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ # Internal: Adds the requested resource to rack's env
4
+ module Hyperdrive
5
+ module Middleware
6
+ class Resource
7
+ def initialize(app, resource)
8
+ @app = app
9
+ @resource = resource
10
+ end
11
+
12
+ def call(env)
13
+ env['hyperdrive.resource'] = @resource
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module Hyperdrive
4
+ module Middleware
5
+ class SanitizeParams
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ unless %w(OPTIONS TRACE).include? env['REQUEST_METHOD']
12
+ request = Rack::Request.new(env)
13
+ params = Hyperdrive::Utils.symbolize_keys(request.params)
14
+ if %w(GET HEAD).include? env['REQUEST_METHOD']
15
+ params_to_keep = env['hyperdrive.resource'].filters.keys
16
+ else
17
+ params_to_keep = env['hyperdrive.resource'].params.keys
18
+ end
19
+ env['hyperdrive.params'] = Hyperdrive::Utils.sanitize_keys(params_to_keep, params)
20
+ end
21
+ @app.call(env)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require 'hyperdrive/middleware/accept'
4
+ require 'hyperdrive/middleware/cors'
5
+ require 'hyperdrive/middleware/content_negotiation'
6
+ require 'hyperdrive/middleware/error'
7
+ require 'hyperdrive/middleware/resource'
8
+ require 'hyperdrive/middleware/request_method'
9
+ require 'hyperdrive/middleware/required_params'
10
+ require 'hyperdrive/middleware/sanitize_params'