apill 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6e916c78acf4e6b77bba21330da5ec51c64dc14
4
- data.tar.gz: 5a52f7ab6a1ab045168db125dccf391fbde97e5b
3
+ metadata.gz: 974dc18ca764506d1a544244dfb65b70ce344ec7
4
+ data.tar.gz: a74c5b8c216e451a7d25015e623363b2b0348b2e
5
5
  SHA512:
6
- metadata.gz: bbf3a7730599ec3d42223988e7e9732532dd72bde970aff017345c1cb4a3b959c7b7ae441f6b14795cac269fe944d9fbdfd92c2567e2f81ae76383bb523406dd
7
- data.tar.gz: 882474601d4956b23b8aa815cc2ca91318639de79d26614e94694902db5c119332dfdfafa7b6ddf48ead4dab0a87a657320f0b4fca8d5766a720b39e92a7c07c
6
+ metadata.gz: 9e248544358f6cf0a0559504b360ca48ba560fdb88a59b23e6007acfddbe67c1c30e7e5de9abcfa3a2191c8d55065af654f4f685151d7c1cce61edc540e7afee
7
+ data.tar.gz: 0cd92dc06458725f440594001bce76f56a00625f88ee2d9afe56981972ac54c4d838ed50eaa1bdbfdbe8f008646bcf02c3614fe2bbe0d2fd4e8f6b99c898eb7b
@@ -0,0 +1,24 @@
1
+ module Apill
2
+ class Configuration
3
+ attr_accessor \
4
+ :allowed_subdomains,
5
+ :application_name,
6
+ :default_api_version
7
+
8
+ def to_h
9
+ {
10
+ allowed_subdomains: allowed_subdomains,
11
+ application_name: application_name,
12
+ default_api_version: api_version,
13
+ }
14
+ end
15
+ end
16
+
17
+ def self.configure
18
+ yield configuration
19
+ end
20
+
21
+ def self.configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'human_error'
2
+
3
+ module Apill
4
+ module Errors
5
+ class InvalidSubdomainError < HumanError::Errors::RequestError
6
+ attr_accessor :http_host
7
+
8
+ def http_status
9
+ 404
10
+ end
11
+
12
+ def developer_message
13
+ 'The resource you attempted to access is either not authorized for the ' \
14
+ 'authenticated user or does not exist.'
15
+ end
16
+
17
+ def developer_details
18
+ { http_host: http_host }
19
+ end
20
+
21
+ def friendly_message
22
+ 'Sorry! The resource you tried to access does not exist.'
23
+ end
24
+ end
25
+ end
26
+ end
@@ -8,7 +8,6 @@ class AcceptHeaderMatcher
8
8
  def matches?(request)
9
9
  super
10
10
 
11
- request.subdomains.first == 'api' &&
12
11
  accept_header.valid?
13
12
  end
14
13
  end
@@ -13,28 +13,31 @@ module GenericMatcher
13
13
  end
14
14
 
15
15
  def matches?(request)
16
- self.accept_header = get_accept_header(raw_header_from_headers: request.headers['Accept'],
17
- raw_header_from_params: request.params['accept'])
16
+ self.application = request['API_APPLICATION_NAME']
17
+ self.accept_header = get_accept_header(raw_header_from_headers: request['HTTP_ACCEPT'],
18
+ raw_header_from_params: request['QUERY_STRING'])
18
19
  end
19
20
 
20
21
  private
21
22
 
22
23
  def get_accept_header(raw_header_from_headers:, raw_header_from_params:)
23
- header_from_header = accept_header_from_header(raw_header_from_headers)
24
+ header_from_header = accept_header_from_string(raw_header_from_headers)
24
25
 
25
- return header_from_header if header_from_header.valid? || raw_header_from_params.nil?
26
+ return header_from_header if header_from_header.valid? ||
27
+ raw_header_from_params.to_s.empty?
26
28
 
27
- accept_header_from_header(raw_header_from_params)
29
+ accept_header_from_params(raw_header_from_params)
28
30
  end
29
31
 
30
- def accept_header_from_header(raw_header_from_headers='')
32
+ def accept_header_from_string(raw_header_from_headers='')
31
33
  Apill::AcceptHeader.new(application: application,
32
34
  header: raw_header_from_headers)
33
35
  end
34
36
 
35
37
  def accept_header_from_params(raw_header_from_params='')
36
- Apill::AcceptHeader.new(application: application,
37
- header: raw_header_from_params)
38
+ header_from_params = raw_header_from_params[%r{(?:\A|&)accept=(.+?)(?=\z|&)}, 1]
39
+
40
+ accept_header_from_string(header_from_params)
38
41
  end
39
42
  end
40
43
  end
@@ -1,17 +1,19 @@
1
1
  module Apill
2
2
  module Matchers
3
3
  class SubdomainMatcher
4
- def initialize(subdomain: 'api')
5
- self.subdomain = subdomain
4
+ def initialize(allowed_subdomains: ['api'])
5
+ self.allowed_subdomains = Array(allowed_subdomains)
6
6
  end
7
7
 
8
8
  def matches?(request)
9
- request.subdomains.first == subdomain
9
+ request_subdomain = request['HTTP_HOST'][/\A([a-z\-]+)/i, 1]
10
+
11
+ allowed_subdomains.include? request_subdomain
10
12
  end
11
13
 
12
14
  protected
13
15
 
14
- attr_accessor :subdomain
16
+ attr_accessor :allowed_subdomains
15
17
  end
16
18
  end
17
19
  end
@@ -1,5 +1,4 @@
1
1
  require 'apill/matchers/generic_matcher'
2
- require 'apill/errors/invalid_api_request_error'
3
2
 
4
3
  module Apill
5
4
  module Matchers
@@ -12,10 +11,7 @@ class VersionMatcher
12
11
  def matches?(request)
13
12
  super
14
13
 
15
- raise Apill::Errors::InvalidApiRequestError unless accept_header.valid?
16
-
17
- request.subdomains.first == 'api' &&
18
- requested_version == version_constraint
14
+ requested_version == version_constraint
19
15
  end
20
16
 
21
17
  private
@@ -0,0 +1,32 @@
1
+ require 'json'
2
+ require 'apill/configuration'
3
+ require 'apill/matchers/subdomain_matcher'
4
+ require 'apill/matchers/invalid_api_request_matcher'
5
+ require 'apill/responses/invalid_api_request_response'
6
+ require 'apill/responses/invalid_subdomain_response'
7
+
8
+ module Apill
9
+ module Middleware
10
+ class ApiRequest
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ env['API_APPLICATION_NAME'] = Apill.configuration.application_name
17
+
18
+ if Matchers::SubdomainMatcher.new(allowed_subdomains: Apill.configuration.allowed_subdomains).
19
+ matches?(env)
20
+
21
+ if Matchers::AcceptHeaderMatcher.new.matches?(env)
22
+ @app.call(env)
23
+ else
24
+ Responses::InvalidApiRequestResponse.call(env)
25
+ end
26
+ else
27
+ Responses::InvalidSubdomainResponse.call(env)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ require 'apill/errors/invalid_subdomain_error'
2
+
3
+ module Apill
4
+ module Responses
5
+ class InvalidSubdomainResponse
6
+ def self.call(env)
7
+ error = Apill::Errors::InvalidSubdomainError.new(http_host: env['HTTP_HOST'])
8
+
9
+ [
10
+ error.http_status, # HTTP Status Code
11
+ {}, # Response Headers
12
+ [ error.to_json ], # Message
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/apill/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Apill
2
- VERSION = '1.6.0'
2
+ VERSION = '2.0.0'
3
3
  end
File without changes
@@ -0,0 +1,39 @@
1
+ require 'rspectacular'
2
+ require 'apill/errors/invalid_subdomain_error'
3
+
4
+ module Apill
5
+ module Errors
6
+ describe InvalidSubdomainError do
7
+ let(:error) { InvalidSubdomainError.new }
8
+
9
+ it 'has a status of 404' do
10
+ expect(error.http_status).to eql 404
11
+ end
12
+
13
+ it 'has a code of 1010' do
14
+ expect(error.code).to eql 1010
15
+ end
16
+
17
+ it 'has a knowledgebase article ID of 1234567890' do
18
+ expect(error.knowledgebase_article_id).to eql '1234567890'
19
+ end
20
+
21
+ it 'can output the developer message' do
22
+ expect(error.developer_message).to eql \
23
+ 'The resource you attempted to access is either not authorized for the ' \
24
+ 'authenticated user or does not exist.'
25
+ end
26
+
27
+ it 'can output the developer details' do
28
+ error = InvalidSubdomainError.new http_host: 'foo'
29
+
30
+ expect(error.developer_details).to eql(http_host: 'foo')
31
+ end
32
+
33
+ it 'can output the friendly message' do
34
+ expect(error.friendly_message).to eql \
35
+ 'Sorry! The resource you tried to access does not exist.'
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ require 'rspectacular'
2
+ require 'apill/responses/invalid_subdomain_response'
3
+
4
+ module Apill
5
+ module Responses
6
+ describe InvalidSubdomainResponse do
7
+ before(:each) do
8
+ HumanError.configuration.api_error_documentation_url = 'http://error.com'
9
+ HumanError.configuration.knowledgebase_url = 'http://knowledge.com'
10
+ HumanError.configuration.api_version = '1'
11
+ end
12
+
13
+ it 'returns the proper response' do
14
+ request = { 'HTTP_HOST' => 'api.example.com' }
15
+ response = InvalidSubdomainResponse.call(request)
16
+
17
+ expect(response).to eql(
18
+ [
19
+ 404,
20
+ {},
21
+ [
22
+ '{' \
23
+ '"error":' \
24
+ '{' \
25
+ '"status":404,' \
26
+ '"code":1010,' \
27
+ '"developer_documentation_uri":"http://error.com/1010?version=1",' \
28
+ '"customer_support_uri":"http://knowledge.com/1234567890",' \
29
+ '"developer_message_key":"errors.invalid.subdomain.error.developer",' \
30
+ '"developer_message":"The resource you attempted to access is either not authorized for the authenticated user or does not exist.",' \
31
+ '"developer_details":' \
32
+ '{' \
33
+ '"http_host":"api.example.com"' \
34
+ '},' \
35
+ '"friendly_message_key":"errors.invalid.subdomain.error.friendly",' \
36
+ '"friendly_message":"Sorry! The resource you tried to access does not exist."' \
37
+ '}' \
38
+ '}'
39
+ ]
40
+ ]
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,103 @@
1
+ require 'rspectacular'
2
+ require 'apill/matchers/accept_header_matcher'
3
+
4
+ module Apill
5
+ module Matchers
6
+ describe AcceptHeaderMatcher do
7
+ it 'matches if the subdomain is API and the accept header is valid' do
8
+ request = {
9
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
10
+ 'API_APPLICATION_NAME' => 'matrix',
11
+ }
12
+
13
+ matcher = AcceptHeaderMatcher.new
14
+
15
+ expect(matcher.matches?(request)).to be_a TrueClass
16
+ end
17
+
18
+ it 'matches if the subdomain is API and the accept header is passed in as ' \
19
+ 'a parameter' do
20
+
21
+ request = {
22
+ 'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
23
+ 'API_APPLICATION_NAME' => 'matrix',
24
+ }
25
+
26
+ matcher = AcceptHeaderMatcher.new
27
+
28
+ expect(matcher.matches?(request)).to be_a TrueClass
29
+ end
30
+
31
+ it 'matches if the subdomain is API and the accept header is passed in as a ' \
32
+ 'secondary parameter' do
33
+
34
+ request = {
35
+ 'QUERY_STRING' => 'first=my_param&accept=application/vnd.matrix+zion;version=1.0.0',
36
+ 'API_APPLICATION_NAME' => 'matrix',
37
+ }
38
+
39
+ matcher = AcceptHeaderMatcher.new
40
+
41
+ expect(matcher.matches?(request)).to be_a TrueClass
42
+ end
43
+
44
+ it 'matches the header accept header if the subdomain is API and the accept header ' \
45
+ 'is passed both as a valid header and as a parameter' do
46
+
47
+ request = {
48
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
49
+ 'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=2.0.0',
50
+ 'API_APPLICATION_NAME' => 'matrix',
51
+ }
52
+
53
+ matcher = AcceptHeaderMatcher.new
54
+ matcher.matches?(request)
55
+
56
+ expect(matcher.accept_header.version).to eql '1.0.0'
57
+ end
58
+
59
+ it 'matches the accept header parameter if the subdomain is API and the accept ' \
60
+ 'header is passed both as an invalid header as well as as a parameter' do
61
+
62
+ request = {
63
+ 'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
64
+ 'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=2.0.0',
65
+ 'API_APPLICATION_NAME' => 'matrix',
66
+ }
67
+
68
+ matcher = AcceptHeaderMatcher.new
69
+ matcher.matches?(request)
70
+
71
+ expect(matcher.accept_header.version).to eql '2.0.0'
72
+ end
73
+
74
+ it 'matches the accept header parameter if the subdomain is API and the accept ' \
75
+ 'header is passed both as an invalid header as well as as a parameter' do
76
+
77
+ request = {
78
+ 'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
79
+ 'QUERY_STRING' => '',
80
+ 'API_APPLICATION_NAME' => 'matrix',
81
+ }
82
+
83
+ matcher = AcceptHeaderMatcher.new
84
+ matcher.matches?(request)
85
+
86
+ expect(matcher.accept_header.raw_accept_header).to eql \
87
+ 'application/vndmatrix+zion;version=1.0.0'
88
+ end
89
+
90
+ it 'does not match if the subdomain is API but the accept header is invalid' do
91
+ request = {
92
+ 'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
93
+ 'QUERY_STRING' => '',
94
+ 'API_APPLICATION_NAME' => 'matrix',
95
+ }
96
+
97
+ matcher = AcceptHeaderMatcher.new
98
+
99
+ expect(matcher.matches?(request)).to be_a FalseClass
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,21 @@
1
+ require 'ostruct'
2
+ require 'rspectacular'
3
+ require 'apill/matchers/invalid_api_request_matcher'
4
+
5
+ module Apill
6
+ module Matchers
7
+ describe InvalidApiRequestMatcher do
8
+ it 'is the inverse of whether the accept header matches' do
9
+ request = {
10
+ 'HTTP_HOST' => 'api.example.com',
11
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
12
+ 'API_APPLICATION_NAME' => 'matrix',
13
+ }
14
+
15
+ matcher = InvalidApiRequestMatcher.new
16
+
17
+ expect(matcher.matches?(request)).to be_a FalseClass
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ require 'rspectacular'
2
+ require 'apill/matchers/subdomain_matcher'
3
+
4
+ module Apill
5
+ module Matchers
6
+ describe SubdomainMatcher do
7
+ it 'matches if the subdomain is API' do
8
+ matcher = SubdomainMatcher.new
9
+ request = { 'HTTP_HOST' => 'api.example.com' }
10
+
11
+ expect(matcher.matches?(request)).to be_a TrueClass
12
+ end
13
+
14
+ it 'matches if the first subdomain is API' do
15
+ matcher = SubdomainMatcher.new
16
+ request = { 'HTTP_HOST' => 'api.matrix.example.com' }
17
+
18
+ expect(matcher.matches?(request)).to be_a TrueClass
19
+ end
20
+
21
+ it 'does not match if the first subdomain is not API' do
22
+ matcher = SubdomainMatcher.new
23
+ request = { 'HTTP_HOST' => 'matrix.example.com' }
24
+
25
+ expect(matcher.matches?(request)).to be_a FalseClass
26
+ end
27
+
28
+ it 'allows the matched subdomain to be specified' do
29
+ matcher = SubdomainMatcher.new(allowed_subdomains: 'matrix')
30
+ request = { 'HTTP_HOST' => 'matrix.example.com' }
31
+
32
+ expect(matcher.matches?(request)).to be_a TrueClass
33
+ end
34
+
35
+ it 'allows more than one subdomain to be matched' do
36
+ matcher = SubdomainMatcher.new(allowed_subdomains: %w{api matrix})
37
+
38
+ request = { 'HTTP_HOST' => 'matrix.example.com' }
39
+ expect(matcher.matches?(request)).to be_a TrueClass
40
+
41
+ request = { 'HTTP_HOST' => 'api.example.com' }
42
+ expect(matcher.matches?(request)).to be_a TrueClass
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,66 @@
1
+ require 'rspectacular'
2
+ require 'apill/matchers/version_matcher'
3
+
4
+ module Apill
5
+ module Matchers
6
+ describe VersionMatcher do
7
+ context 'when the version is passed in the accept header' do
8
+ it 'does not match if the subdomain is API but the requested version does not ' \
9
+ 'equal the version constraint' do
10
+
11
+ request = {
12
+ 'API_APPLICATION_NAME' => 'matrix',
13
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=10.0',
14
+ }
15
+
16
+ matcher = VersionMatcher.new(version_constraint: '10.1')
17
+
18
+ expect(matcher.matches?(request)).to be_a FalseClass
19
+ end
20
+
21
+ it 'does match if the subdomain is API and the requested version equals the ' \
22
+ 'version constraint' do
23
+
24
+ request = {
25
+ 'API_APPLICATION_NAME' => 'matrix',
26
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=10.0',
27
+ }
28
+
29
+ matcher = VersionMatcher.new(version_constraint: '10.0')
30
+
31
+ expect(matcher.matches?(request)).to be_a TrueClass
32
+ end
33
+ end
34
+
35
+ context 'when the version is not passed in the accept header' do
36
+ it 'does not match if the subdomain is API but the requested version does not ' \
37
+ 'equal the version constraint' do
38
+
39
+ request = {
40
+ 'API_APPLICATION_NAME' => 'matrix',
41
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion',
42
+ }
43
+
44
+ matcher = VersionMatcher.new(version_constraint: '10.1',
45
+ default_version: '10.0')
46
+
47
+ expect(matcher.matches?(request)).to be_a FalseClass
48
+ end
49
+
50
+ it 'does match if the subdomain is API and the requested version equals the ' \
51
+ 'version constraint' do
52
+
53
+ request = {
54
+ 'API_APPLICATION_NAME' => 'matrix',
55
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion',
56
+ }
57
+
58
+ matcher = VersionMatcher.new(version_constraint: '10.0',
59
+ default_version: '10.0')
60
+
61
+ expect(matcher.matches?(request)).to be_a TrueClass
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,114 @@
1
+ require 'rspectacular'
2
+ require 'apill/middleware/api_request'
3
+
4
+ HumanError.configure do |config|
5
+ config.api_error_documentation_url = 'http://error.com'
6
+ config.knowledgebase_url = 'http://knowledge.com'
7
+ config.api_version = '1'
8
+ end
9
+
10
+ Apill.configure do |config|
11
+ config.allowed_subdomains = %w{api}
12
+ config.application_name = 'matrix'
13
+ end
14
+
15
+ module Apill
16
+ module Middleware
17
+ describe ApiRequest do
18
+ let(:app) { lambda { |env| [200, {}, 'response'] } }
19
+
20
+ it 'does not allow requests if they are not for an allowed subdomain' do
21
+ api_request_middleware = ApiRequest.new(app)
22
+
23
+ request = {
24
+ 'HTTP_HOST' => 'notvalid.example.com',
25
+ 'HTTP_ACCEPT' => '',
26
+ 'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+zion;version=1.0.0',
27
+ 'API_APPLICATION_NAME' => 'matrix',
28
+ }
29
+
30
+ status, headers, response = api_request_middleware.call(request)
31
+
32
+ expect(status).to eql 404
33
+ expect(headers).to eql Hash.new
34
+ expect(response).to eql(
35
+ [
36
+ '{' \
37
+ '"error":' \
38
+ '{' \
39
+ '"status":404,' \
40
+ '"code":1010,' \
41
+ '"developer_documentation_uri":"http://error.com/1010?version=1",' \
42
+ '"customer_support_uri":"http://knowledge.com/1234567890",' \
43
+ '"developer_message_key":"errors.invalid.subdomain.error.developer",' \
44
+ '"developer_message":"The resource you attempted to access is either not authorized for the authenticated user or does not exist.",' \
45
+ '"developer_details":' \
46
+ '{' \
47
+ '"http_host":"notvalid.example.com"' \
48
+ '},' \
49
+ '"friendly_message_key":"errors.invalid.subdomain.error.friendly",' \
50
+ '"friendly_message":"Sorry! The resource you tried to access does not exist."' \
51
+ '}' \
52
+ '}'
53
+ ]
54
+ )
55
+ end
56
+
57
+ it 'does not allow requests if they are for an allowed subdomain but does ' \
58
+ 'not have a valid accept header' do
59
+
60
+ api_request_middleware = ApiRequest.new(app)
61
+
62
+ request = {
63
+ 'HTTP_HOST' => 'api.example.com',
64
+ 'HTTP_ACCEPT' => '',
65
+ 'QUERY_STRING' => 'first=my_param&accept=application/vnd.silent+zion;version=1.0.0',
66
+ 'API_APPLICATION_NAME' => 'matrix',
67
+ }
68
+
69
+ status, headers, response = api_request_middleware.call(request)
70
+
71
+ expect(status).to eql 400
72
+ expect(headers).to eql Hash.new
73
+ expect(response).to eql(
74
+ [
75
+ '{' \
76
+ '"error":' \
77
+ '{' \
78
+ '"status":400,' \
79
+ '"code":1007,' \
80
+ '"developer_documentation_uri":"http://error.com/1007?version=1",' \
81
+ '"customer_support_uri":"http://knowledge.com/1234567890",' \
82
+ '"developer_message_key":"errors.invalid.api.request.error.developer",' \
83
+ '"developer_message":"The accept header that you passed in the request cannot be parsed, please refer to the documentation to verify.",' \
84
+ '"developer_details":' \
85
+ '{' \
86
+ '"accept_header":""' \
87
+ '},' \
88
+ '"friendly_message_key":"errors.invalid.api.request.error.friendly",' \
89
+ '"friendly_message":"Sorry! We couldn\'t understand what you were trying to ask us to do."' \
90
+ '}' \
91
+ '}'
92
+ ]
93
+ )
94
+ end
95
+
96
+ it 'does allow requests if both the subdomain and the accept header are valid' do
97
+ api_request_middleware = ApiRequest.new(app)
98
+
99
+ request = {
100
+ 'HTTP_HOST' => 'api.example.com',
101
+ 'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
102
+ 'QUERY_STRING' => 'first=my_param&accept=application/vnd.matrix+zion;version=1.0.0',
103
+ 'API_APPLICATION_NAME' => 'matrix',
104
+ }
105
+
106
+ status, headers, response = api_request_middleware.call(request)
107
+
108
+ expect(status).to eql 200
109
+ expect(headers).to eql Hash.new
110
+ expect(response).to eql 'response'
111
+ end
112
+ end
113
+ end
114
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apill
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - jfelchner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-28 00:00:00.000000000 Z
11
+ date: 2014-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: human_error
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.11'
19
+ version: '1.13'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.11'
26
+ version: '1.13'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,47 +44,66 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.38'
47
+ version: '0.50'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.38'
54
+ version: '0.50'
55
+ - !ruby/object:Gem::Dependency
56
+ name: codeclimate-test-reporter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.3.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.3.0
55
69
  description: ''
56
70
  email: accounts+git@thekompanee.com
57
71
  executables: []
58
72
  extensions: []
59
- extra_rdoc_files:
60
- - README.md
61
- - LICENSE
73
+ extra_rdoc_files: []
62
74
  files:
63
75
  - LICENSE
64
76
  - README.md
65
77
  - Rakefile
66
78
  - lib/apill.rb
67
79
  - lib/apill/accept_header.rb
80
+ - lib/apill/configuration.rb
68
81
  - lib/apill/errors/invalid_api_request_error.rb
82
+ - lib/apill/errors/invalid_subdomain_error.rb
69
83
  - lib/apill/matchers/accept_header_matcher.rb
70
84
  - lib/apill/matchers/generic_matcher.rb
71
85
  - lib/apill/matchers/invalid_api_request_matcher.rb
72
86
  - lib/apill/matchers/subdomain_matcher.rb
73
87
  - lib/apill/matchers/version_matcher.rb
88
+ - lib/apill/middleware/api_request.rb
74
89
  - lib/apill/responses/invalid_api_request_response.rb
90
+ - lib/apill/responses/invalid_subdomain_response.rb
75
91
  - lib/apill/version.rb
76
- - spec/lib/apill/accept_header_spec.rb
77
- - spec/lib/apill/errors/invalid_api_request_error_spec.rb
78
- - spec/lib/apill/matchers/accept_header_matcher_spec.rb
79
- - spec/lib/apill/matchers/invalid_api_request_matcher_spec.rb
80
- - spec/lib/apill/matchers/subdomain_matcher_spec.rb
81
- - spec/lib/apill/matchers/version_matcher_spec.rb
92
+ - spec/apill/accept_header_spec.rb
93
+ - spec/apill/errors/invalid_api_request_error_spec.rb
94
+ - spec/apill/errors/invalid_subdomain_error_spec.rb
95
+ - spec/apill/invalid_subdomain_response_spec.rb
96
+ - spec/apill/matchers/accept_header_matcher_spec.rb
97
+ - spec/apill/matchers/invalid_api_request_matcher_spec.rb
98
+ - spec/apill/matchers/subdomain_matcher_spec.rb
99
+ - spec/apill/matchers/version_matcher_spec.rb
100
+ - spec/apill/middleware/api_request_spec.rb
82
101
  homepage: https://github.com/jfelchner/apill
83
- licenses: []
102
+ licenses:
103
+ - MIT
84
104
  metadata: {}
85
105
  post_install_message:
86
- rdoc_options:
87
- - "--charset = UTF-8"
106
+ rdoc_options: []
88
107
  require_paths:
89
108
  - lib
90
109
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -98,16 +117,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
117
  - !ruby/object:Gem::Version
99
118
  version: '0'
100
119
  requirements: []
101
- rubyforge_project: apill
102
- rubygems_version: 2.3.0
120
+ rubyforge_project:
121
+ rubygems_version: 2.4.2
103
122
  signing_key:
104
123
  specification_version: 4
105
124
  summary: Common API functionality
106
125
  test_files:
107
- - spec/lib/apill/accept_header_spec.rb
108
- - spec/lib/apill/errors/invalid_api_request_error_spec.rb
109
- - spec/lib/apill/matchers/accept_header_matcher_spec.rb
110
- - spec/lib/apill/matchers/invalid_api_request_matcher_spec.rb
111
- - spec/lib/apill/matchers/subdomain_matcher_spec.rb
112
- - spec/lib/apill/matchers/version_matcher_spec.rb
126
+ - spec/apill/accept_header_spec.rb
127
+ - spec/apill/errors/invalid_api_request_error_spec.rb
128
+ - spec/apill/errors/invalid_subdomain_error_spec.rb
129
+ - spec/apill/invalid_subdomain_response_spec.rb
130
+ - spec/apill/matchers/accept_header_matcher_spec.rb
131
+ - spec/apill/matchers/invalid_api_request_matcher_spec.rb
132
+ - spec/apill/matchers/subdomain_matcher_spec.rb
133
+ - spec/apill/matchers/version_matcher_spec.rb
134
+ - spec/apill/middleware/api_request_spec.rb
113
135
  has_rdoc:
@@ -1,92 +0,0 @@
1
- require 'ostruct'
2
- require 'rspectacular'
3
- require 'apill/matchers/accept_header_matcher'
4
-
5
- module Apill
6
- module Matchers
7
- describe AcceptHeaderMatcher do
8
- it 'matches if the subdomain is API and the accept header is valid' do
9
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=1.0.0' },
10
- params: {},
11
- subdomains: [ 'api' ])
12
-
13
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
14
-
15
- expect(matcher.matches?(request)).to be_truthy
16
- end
17
-
18
- it 'matches if the subdomain is API and the accept header is passed in as a parameter' do
19
- request = OpenStruct.new(headers: {},
20
- params: { 'accept' => 'application/vnd.matrix+zion;version=1.0.0' },
21
- subdomains: [ 'api' ])
22
-
23
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
24
-
25
- expect(matcher.matches?(request)).to be_truthy
26
- end
27
-
28
- it 'matches the header accept header if the subdomain is API and the accept header is passed both as a valid header and as a parameter' do
29
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=1.0.0' },
30
- params: { 'accept' => 'application/vnd.matrix+zion;version=2.0.0' },
31
- subdomains: [ 'api' ])
32
-
33
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
34
- matcher.matches?(request)
35
-
36
- expect(matcher.accept_header.version).to eql '1.0.0'
37
- end
38
-
39
- it "matches the parameter's accept header if the subdomain is API and the accept header is passed both as an invalid header as well as as a parameter" do
40
- request = OpenStruct.new(headers: { 'Accept' => 'application/vndmatrix+zion;version=1.0.0' },
41
- params: { 'accept' => 'application/vnd.matrix+zion;version=2.0.0' },
42
- subdomains: [ 'api' ])
43
-
44
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
45
- matcher.matches?(request)
46
-
47
- expect(matcher.accept_header.version).to eql '2.0.0'
48
- end
49
-
50
- it "matches the parameter's accept header if the subdomain is API and the accept header is passed both as an invalid header as well as as a parameter" do
51
- request = OpenStruct.new(headers: { 'Accept' => 'application/vndmatrix+zion;version=1.0.0' },
52
- params: {},
53
- subdomains: [ 'api' ])
54
-
55
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
56
- matcher.matches?(request)
57
-
58
- expect(matcher.accept_header.raw_accept_header).to eql 'application/vndmatrix+zion;version=1.0.0'
59
- end
60
-
61
- it 'does not match if the subdomain is not API but the accept header is valid' do
62
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion' },
63
- params: {},
64
- subdomains: [ 'not-api' ])
65
-
66
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
67
-
68
- expect(matcher.matches?(request)).to be_falsey
69
- end
70
-
71
- it 'does not match if the subdomain is API but the accept header is invalid' do
72
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.' },
73
- params: {},
74
- subdomains: [ 'api' ])
75
-
76
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
77
-
78
- expect(matcher.matches?(request)).to be_falsey
79
- end
80
-
81
- it 'does not match if neither the subdomain is API nor the accept header is valid' do
82
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.' },
83
- params: {},
84
- subdomains: [ 'not-api' ])
85
-
86
- matcher = AcceptHeaderMatcher.new(application: 'matrix')
87
-
88
- expect(matcher.matches?(request)).to be_falsey
89
- end
90
- end
91
- end
92
- end
@@ -1,19 +0,0 @@
1
- require 'ostruct'
2
- require 'rspectacular'
3
- require 'apill/matchers/invalid_api_request_matcher'
4
-
5
- module Apill
6
- module Matchers
7
- describe InvalidApiRequestMatcher do
8
- it 'is the inverse of whether the accept header matches' do
9
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=1.0.0' },
10
- subdomains: [ 'api' ],
11
- params: {})
12
-
13
- matcher = InvalidApiRequestMatcher.new(application: 'matrix')
14
-
15
- expect(matcher.matches?(request)).to be_falsey
16
- end
17
- end
18
- end
19
- end
@@ -1,41 +0,0 @@
1
- require 'ostruct'
2
- require 'rspectacular'
3
- require 'apill/matchers/subdomain_matcher'
4
-
5
- module Apill
6
- module Matchers
7
- describe SubdomainMatcher do
8
- it 'matches if the subdomain is API' do
9
- request = OpenStruct.new(subdomains: [ 'api' ])
10
-
11
- matcher = SubdomainMatcher.new
12
-
13
- expect(matcher.matches?(request)).to be_truthy
14
- end
15
-
16
- it 'matches if the first subdomain is API' do
17
- request = OpenStruct.new(subdomains: [ 'api', 'matrix' ])
18
-
19
- matcher = SubdomainMatcher.new
20
-
21
- expect(matcher.matches?(request)).to be_truthy
22
- end
23
-
24
- it 'does not match if the first subdomain is not API' do
25
- request = OpenStruct.new(subdomains: [ 'matrix' ])
26
-
27
- matcher = SubdomainMatcher.new
28
-
29
- expect(matcher.matches?(request)).to be_falsey
30
- end
31
-
32
- it 'allows the matched subdomain to be specified' do
33
- request = OpenStruct.new(subdomains: [ 'matrix' ])
34
-
35
- matcher = SubdomainMatcher.new(subdomain: 'matrix')
36
-
37
- expect(matcher.matches?(request)).to be_truthy
38
- end
39
- end
40
- end
41
- end
@@ -1,92 +0,0 @@
1
- require 'ostruct'
2
- require 'rspectacular'
3
- require 'apill/matchers/version_matcher'
4
-
5
- module Apill
6
- module Matchers
7
- describe VersionMatcher do
8
- it 'raises an error when the accept header is not valid' do
9
- request = OpenStruct.new(headers: { 'Accept' => 'matrix' },
10
- subdomains: [ 'api' ],
11
- params: {})
12
-
13
- matcher = VersionMatcher.new
14
-
15
- expect { matcher.matches?(request) }.to raise_error Apill::Errors::InvalidApiRequestError
16
- end
17
-
18
- context 'when the version is passed in the accept header' do
19
- it 'does not match if the subdomain is not API but the request version is equal to the version constraint' do
20
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=10.0' },
21
- subdomains: [ 'not-api' ],
22
- params: {})
23
-
24
- matcher = VersionMatcher.new(application: 'matrix',
25
- version_constraint: '10.0')
26
-
27
- expect(matcher.matches?(request)).to be_falsey
28
- end
29
-
30
- it 'does not match if the subdomain is API but the requested version does not equal the version constraint' do
31
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=10.0' },
32
- subdomains: [ 'api' ],
33
- params: {})
34
-
35
- matcher = VersionMatcher.new(application: 'matrix',
36
- version_constraint: '10.1')
37
-
38
- expect(matcher.matches?(request)).to be_falsey
39
- end
40
-
41
- it 'does match if the subdomain is API and the requested version equals the version constraint' do
42
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion;version=10.0' },
43
- subdomains: [ 'api' ],
44
- params: {})
45
-
46
- matcher = VersionMatcher.new(application: 'matrix',
47
- version_constraint: '10.0')
48
-
49
- expect(matcher.matches?(request)).to be_truthy
50
- end
51
- end
52
-
53
- context 'when the version is not passed in the accept header' do
54
- it 'does not match if the subdomain is not API but the request version is equal to the version constraint' do
55
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion' },
56
- subdomains: [ 'not-api' ],
57
- params: {})
58
-
59
- matcher = VersionMatcher.new(application: 'matrix',
60
- version_constraint: '10.0',
61
- default_version: '10.0')
62
-
63
- expect(matcher.matches?(request)).to be_falsey
64
- end
65
-
66
- it 'does not match if the subdomain is API but the requested version does not equal the version constraint' do
67
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion' },
68
- subdomains: [ 'api' ],
69
- params: {})
70
-
71
- matcher = VersionMatcher.new(application: 'matrix',
72
- version_constraint: '10.1',
73
- default_version: '10.0')
74
-
75
- expect(matcher.matches?(request)).to be_falsey
76
- end
77
-
78
- it 'does match if the subdomain is API and the requested version equals the version constraint' do
79
- request = OpenStruct.new(headers: { 'Accept' => 'application/vnd.matrix+zion' },
80
- subdomains: [ 'api' ],
81
- params: {})
82
-
83
- matcher = VersionMatcher.new(application: 'matrix',
84
- version_constraint: '10.0',
85
- default_version: '10.0')
86
-
87
- expect(matcher.matches?(request)).to be_truthy
88
- end
89
- end
90
- end
91
- end
92
- end