apill 3.1.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/apill/configuration.rb +2 -1
- data/lib/apill/errors/{invalid_api_request_error.rb → invalid_api_request.rb} +1 -1
- data/lib/apill/errors/{invalid_subdomain_error.rb → invalid_subdomain.rb} +1 -1
- data/lib/apill/errors/invalid_token.rb +21 -0
- data/lib/apill/matchers/accept_header.rb +13 -0
- data/lib/apill/matchers/{generic_matcher.rb → generic.rb} +5 -9
- data/lib/apill/matchers/{subdomain_matcher.rb → subdomain.rb} +3 -9
- data/lib/apill/matchers/{version_matcher.rb → version.rb} +4 -6
- data/lib/apill/middleware/api_request.rb +22 -21
- data/lib/apill/parameters/index.rb +1 -1
- data/lib/apill/parameters/page.rb +1 -1
- data/lib/apill/parameters/sort.rb +1 -1
- data/lib/apill/requests/base.rb +86 -10
- data/lib/apill/requests/rack.rb +34 -0
- data/lib/apill/requests/rails.rb +31 -0
- data/lib/apill/resource/model.rb +1 -1
- data/lib/apill/resource/processors/filtering.rb +2 -0
- data/lib/apill/resource/processors/indexing.rb +2 -0
- data/lib/apill/resource/processors/paging.rb +2 -0
- data/lib/apill/resource/processors/sorting.rb +2 -0
- data/lib/apill/responses/{invalid_subdomain_response.rb → invalid_api_request.rb} +3 -3
- data/lib/apill/responses/{invalid_api_request_response.rb → invalid_subdomain.rb} +3 -3
- data/lib/apill/responses/invalid_token.rb +17 -0
- data/lib/apill/tokens/invalid_request_authorization.rb +21 -0
- data/lib/apill/tokens/null_request_authorization.rb +21 -0
- data/lib/apill/tokens/request_authorization.rb +62 -0
- data/lib/apill/version.rb +1 -1
- data/lib/apill.rb +5 -5
- data/spec/apill/accept_header_spec.rb +1 -1
- data/spec/apill/errors/{invalid_api_request_error_spec.rb → invalid_api_request_spec.rb} +6 -6
- data/spec/apill/errors/{invalid_subdomain_error_spec.rb → invalid_subdomain_spec.rb} +6 -6
- data/spec/apill/errors/invalid_token_spec.rb +23 -0
- data/spec/apill/{invalid_subdomain_response_spec.rb → invalid_subdomain_spec.rb} +7 -7
- data/spec/apill/invalid_token_spec.rb +42 -0
- data/spec/apill/matchers/{accept_header_matcher_spec.rb → accept_header_spec.rb} +32 -24
- data/spec/apill/matchers/subdomain_spec.rb +81 -0
- data/spec/apill/matchers/{version_matcher_spec.rb → version_spec.rb} +31 -20
- data/spec/apill/middleware/api_request_spec.rb +36 -38
- data/spec/apill/parameters_spec.rb +1 -1
- data/spec/apill/requests/rack_spec.rb +159 -0
- data/spec/apill/requests/rails_spec.rb +151 -0
- data/spec/apill/resource/model_spec.rb +1 -1
- data/spec/apill/resource/processors/filtering_spec.rb +1 -1
- data/spec/apill/resource/processors/indexing_spec.rb +1 -1
- data/spec/apill/resource/processors/paging_spec.rb +1 -1
- data/spec/apill/resource/processors/sorting_spec.rb +1 -1
- data/spec/apill/tokens/request_authorization_spec.rb +49 -0
- data/spec/fixtures/test_rsa_key +27 -0
- data/spec/fixtures/test_rsa_key.pub +9 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/private_keys.rb +19 -0
- metadata +75 -29
- data/lib/apill/matchers/accept_header_matcher.rb +0 -15
- data/lib/apill/requests/rack_request.rb +0 -37
- data/lib/apill/requests/rails_request.rb +0 -29
- data/spec/apill/matchers/subdomain_matcher_spec.rb +0 -72
- data/spec/apill/requests/rack_request_spec.rb +0 -70
- data/spec/apill/requests/rails_request_spec.rb +0 -59
data/lib/apill.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'apill/version'
|
2
2
|
|
3
3
|
require 'apill/configuration'
|
4
|
-
require 'apill/matchers/
|
5
|
-
require 'apill/matchers/
|
6
|
-
require 'apill/matchers/
|
4
|
+
require 'apill/matchers/accept_header'
|
5
|
+
require 'apill/matchers/subdomain'
|
6
|
+
require 'apill/matchers/version'
|
7
7
|
require 'apill/resource'
|
8
8
|
require 'apill/serializers/json_api'
|
9
9
|
|
10
10
|
require 'apill/middleware/api_request'
|
11
11
|
|
12
|
-
require 'apill/responses/
|
13
|
-
require 'apill/responses/
|
12
|
+
require 'apill/responses/invalid_api_request'
|
13
|
+
require 'apill/responses/invalid_subdomain'
|
@@ -1,17 +1,17 @@
|
|
1
|
-
require '
|
2
|
-
require 'apill/errors/
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/errors/invalid_api_request'
|
3
3
|
|
4
4
|
module Apill
|
5
5
|
module Errors
|
6
|
-
describe
|
7
|
-
let(:error) {
|
6
|
+
describe InvalidApiRequest do
|
7
|
+
let(:error) { InvalidApiRequest.new }
|
8
8
|
|
9
9
|
it 'has a status of 400' do
|
10
10
|
expect(error.http_status).to eql 400
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'has a code' do
|
14
|
-
expect(error.code).to eql 'errors.
|
14
|
+
expect(error.code).to eql 'errors.invalid_api_request'
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'can output the detail' do
|
@@ -21,7 +21,7 @@ describe InvalidApiRequestError do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'can output the source' do
|
24
|
-
error =
|
24
|
+
error = InvalidApiRequest.new accept_header: 'foo'
|
25
25
|
|
26
26
|
expect(error.source).to eql(accept_header: 'foo')
|
27
27
|
end
|
@@ -1,17 +1,17 @@
|
|
1
|
-
require '
|
2
|
-
require 'apill/errors/
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/errors/invalid_subdomain'
|
3
3
|
|
4
4
|
module Apill
|
5
5
|
module Errors
|
6
|
-
describe
|
7
|
-
let(:error) {
|
6
|
+
describe InvalidSubdomain do
|
7
|
+
let(:error) { InvalidSubdomain.new }
|
8
8
|
|
9
9
|
it 'has a status of 404' do
|
10
10
|
expect(error.http_status).to eql 404
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'has a code' do
|
14
|
-
expect(error.code).to eql 'errors.
|
14
|
+
expect(error.code).to eql 'errors.invalid_subdomain'
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'can output the detail' do
|
@@ -21,7 +21,7 @@ describe InvalidSubdomainError do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'can output the source' do
|
24
|
-
error =
|
24
|
+
error = InvalidSubdomain.new http_host: 'foo'
|
25
25
|
|
26
26
|
expect(error.source).to eql(http_host: 'foo')
|
27
27
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/errors/invalid_token'
|
3
|
+
|
4
|
+
module Apill
|
5
|
+
module Errors
|
6
|
+
describe InvalidToken do
|
7
|
+
let(:error) { InvalidToken.new }
|
8
|
+
|
9
|
+
it 'has a status of 401' do
|
10
|
+
expect(error.http_status).to eql 401
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has a code' do
|
14
|
+
expect(error.code).to eql 'errors.invalid_token'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can output the detail' do
|
18
|
+
expect(error.detail).to eql \
|
19
|
+
'Either the token you passed is invalid or is not allowed to perform this action.'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
require 'apill/responses/
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/responses/invalid_subdomain'
|
3
3
|
|
4
4
|
module Apill
|
5
5
|
module Responses
|
6
|
-
describe
|
6
|
+
describe InvalidSubdomain, singletons: HumanError::Configuration do
|
7
7
|
it 'returns the proper response' do
|
8
8
|
HumanError.configuration.url_mappings = {
|
9
9
|
'external_documentation_urls' => {
|
10
|
-
'errors.
|
10
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
11
11
|
},
|
12
12
|
'developer_documentation_urls' => {
|
13
|
-
'errors.
|
13
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
14
14
|
},
|
15
15
|
}
|
16
16
|
|
17
17
|
request = { 'HTTP_HOST' => 'api.example.com' }
|
18
|
-
status, headers, response =
|
18
|
+
status, headers, response = InvalidSubdomain.call(request)
|
19
19
|
|
20
20
|
expect(status).to eql 404
|
21
21
|
expect(headers).to eql({})
|
@@ -28,7 +28,7 @@ describe InvalidSubdomainResponse, singletons: HumanError::Configuration do
|
|
28
28
|
'documentation' => nil,
|
29
29
|
},
|
30
30
|
'status' => 404,
|
31
|
-
'code' => 'errors.
|
31
|
+
'code' => 'errors.invalid_subdomain',
|
32
32
|
'title' => 'Invalid Subdomain',
|
33
33
|
'detail' => 'The resource you attempted to access is either not authorized ' \
|
34
34
|
'for the authenticated user or does not exist.',
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/responses/invalid_token'
|
3
|
+
|
4
|
+
module Apill
|
5
|
+
module Responses
|
6
|
+
describe InvalidToken, singletons: HumanError::Configuration do
|
7
|
+
it 'returns the proper response' do
|
8
|
+
HumanError.configuration.url_mappings = {
|
9
|
+
'external_documentation_urls' => {
|
10
|
+
'errors.responses.invalid_token' => 'http://example.com/foo',
|
11
|
+
},
|
12
|
+
'developer_documentation_urls' => {
|
13
|
+
'errors.responses.invalid_token' => 'http://example.com/foo',
|
14
|
+
},
|
15
|
+
}
|
16
|
+
|
17
|
+
request = { 'HTTP_HOST' => 'api.example.com' }
|
18
|
+
status, headers, response = InvalidToken.call(request)
|
19
|
+
|
20
|
+
expect(status).to eql 401
|
21
|
+
expect(headers).to eql({})
|
22
|
+
expect(JSON.load(response[0])).to include(
|
23
|
+
'errors' => [
|
24
|
+
include(
|
25
|
+
'id' => match(/[a-f0-9\-]+/),
|
26
|
+
'links' => {
|
27
|
+
'about' => nil,
|
28
|
+
'documentation' => nil,
|
29
|
+
},
|
30
|
+
'status' => 401,
|
31
|
+
'code' => 'errors.invalid_token',
|
32
|
+
'title' => 'Invalid or Unauthorized Token',
|
33
|
+
'detail' => 'Either the token you passed is invalid or is not allowed to ' \
|
34
|
+
'perform this action.',
|
35
|
+
'source' => {},
|
36
|
+
),
|
37
|
+
],
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,58 +1,63 @@
|
|
1
|
-
require '
|
2
|
-
require 'apill/
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/requests/base'
|
3
|
+
require 'apill/matchers/accept_header'
|
3
4
|
|
4
5
|
module Apill
|
5
6
|
module Matchers
|
6
|
-
describe
|
7
|
+
describe AcceptHeader do
|
7
8
|
it 'matches if the subdomain is API and the accept header is valid' do
|
8
|
-
|
9
|
+
env = {
|
9
10
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
10
11
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
11
12
|
}
|
13
|
+
request = Requests::Base.resolve(env)
|
12
14
|
|
13
|
-
matcher =
|
15
|
+
matcher = AcceptHeader.new(request: request)
|
14
16
|
|
15
|
-
expect(matcher
|
17
|
+
expect(matcher).to be_matches
|
16
18
|
end
|
17
19
|
|
18
20
|
it 'matches if the subdomain is API and the accept header is passed in as ' \
|
19
21
|
'a parameter' do
|
20
22
|
|
21
|
-
|
23
|
+
env = {
|
22
24
|
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
|
23
25
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
24
26
|
}
|
27
|
+
request = Requests::Base.resolve(env)
|
25
28
|
|
26
|
-
matcher =
|
29
|
+
matcher = AcceptHeader.new(request: request)
|
27
30
|
|
28
|
-
expect(matcher
|
31
|
+
expect(matcher).to be_matches
|
29
32
|
end
|
30
33
|
|
31
34
|
it 'matches if the subdomain is API and the accept header is passed in as a ' \
|
32
35
|
'secondary parameter' do
|
33
36
|
|
34
|
-
|
37
|
+
env = {
|
35
38
|
'QUERY_STRING' => 'first=my_param&accept=application/vnd.matrix+zion;' \
|
36
39
|
'version=1.0.0',
|
37
40
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
38
41
|
}
|
42
|
+
request = Requests::Base.resolve(env)
|
39
43
|
|
40
|
-
matcher =
|
44
|
+
matcher = AcceptHeader.new(request: request)
|
41
45
|
|
42
|
-
expect(matcher
|
46
|
+
expect(matcher).to be_matches
|
43
47
|
end
|
44
48
|
|
45
49
|
it 'matches the header accept header if the subdomain is API and the accept header ' \
|
46
50
|
'is passed both as a valid header and as a parameter' do
|
47
51
|
|
48
|
-
|
52
|
+
env = {
|
49
53
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
50
54
|
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=2.0.0',
|
51
55
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
52
56
|
}
|
57
|
+
request = Requests::Base.resolve(env)
|
53
58
|
|
54
|
-
matcher =
|
55
|
-
matcher.matches?
|
59
|
+
matcher = AcceptHeader.new(request: request)
|
60
|
+
matcher.matches?
|
56
61
|
|
57
62
|
expect(matcher.accept_header.version).to eql '1.0.0'
|
58
63
|
end
|
@@ -60,14 +65,15 @@ describe AcceptHeaderMatcher do
|
|
60
65
|
it 'matches the accept header parameter if the subdomain is API and the accept ' \
|
61
66
|
'header is passed both as an invalid header as well as as a parameter' do
|
62
67
|
|
63
|
-
|
68
|
+
env = {
|
64
69
|
'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
|
65
70
|
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=2.0.0',
|
66
71
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
67
72
|
}
|
73
|
+
request = Requests::Base.resolve(env)
|
68
74
|
|
69
|
-
matcher =
|
70
|
-
matcher.matches?
|
75
|
+
matcher = AcceptHeader.new(request: request)
|
76
|
+
matcher.matches?
|
71
77
|
|
72
78
|
expect(matcher.accept_header.version).to eql '2.0.0'
|
73
79
|
end
|
@@ -75,29 +81,31 @@ describe AcceptHeaderMatcher do
|
|
75
81
|
it 'matches the accept header parameter if the subdomain is API and the accept ' \
|
76
82
|
'header is passed both as an invalid header as well as as a parameter' do
|
77
83
|
|
78
|
-
|
84
|
+
env = {
|
79
85
|
'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
|
80
86
|
'QUERY_STRING' => '',
|
81
87
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
82
88
|
}
|
89
|
+
request = Requests::Base.resolve(env)
|
83
90
|
|
84
|
-
matcher =
|
85
|
-
matcher.matches?
|
91
|
+
matcher = AcceptHeader.new(request: request)
|
92
|
+
matcher.matches?
|
86
93
|
|
87
94
|
expect(matcher.accept_header.raw_accept_header).to eql \
|
88
95
|
'application/vndmatrix+zion;version=1.0.0'
|
89
96
|
end
|
90
97
|
|
91
98
|
it 'does not match if the subdomain is API but the accept header is invalid' do
|
92
|
-
|
99
|
+
env = {
|
93
100
|
'HTTP_ACCEPT' => 'application/vndmatrix+zion;version=1.0.0',
|
94
101
|
'QUERY_STRING' => '',
|
95
102
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
96
103
|
}
|
104
|
+
request = Requests::Base.resolve(env)
|
97
105
|
|
98
|
-
matcher =
|
106
|
+
matcher = AcceptHeader.new(request: request)
|
99
107
|
|
100
|
-
expect(matcher
|
108
|
+
expect(matcher).not_to be_matches
|
101
109
|
end
|
102
110
|
end
|
103
111
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/requests/base'
|
3
|
+
require 'apill/matchers/subdomain'
|
4
|
+
require 'apill/configuration'
|
5
|
+
|
6
|
+
module Apill
|
7
|
+
module Matchers
|
8
|
+
describe Subdomain do
|
9
|
+
before(:each) do
|
10
|
+
Apill.configuration.allowed_subdomains = %w{api}
|
11
|
+
Apill.configuration.allowed_api_subdomains = %w{api}
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'matches if the subdomain is API' do
|
15
|
+
env = { 'HTTP_HOST' => 'api.example.com' }
|
16
|
+
request = Requests::Base.resolve(env)
|
17
|
+
matcher = Subdomain.new(request: request)
|
18
|
+
|
19
|
+
expect(matcher.matches?).to be_a TrueClass
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'matches if the first subdomain is API' do
|
23
|
+
env = { 'HTTP_HOST' => 'api.matrix.example.com' }
|
24
|
+
request = Requests::Base.resolve(env)
|
25
|
+
matcher = Subdomain.new(request: request)
|
26
|
+
|
27
|
+
expect(matcher.matches?).to be_a TrueClass
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'does not match if the first subdomain is not API' do
|
31
|
+
env = { 'HTTP_HOST' => 'matrix.example.com' }
|
32
|
+
request = Requests::Base.resolve(env)
|
33
|
+
matcher = Subdomain.new(request: request)
|
34
|
+
|
35
|
+
expect(matcher.matches?).to be_a FalseClass
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'allows the matched subdomain to be specified' do
|
39
|
+
env = { 'HTTP_HOST' => 'matrix.example.com' }
|
40
|
+
request = Requests::Base.resolve(env)
|
41
|
+
matcher = Subdomain.new(allowed_subdomains: 'matrix',
|
42
|
+
request: request)
|
43
|
+
|
44
|
+
expect(matcher.matches?).to be_a TrueClass
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'allows more than one subdomain to be matched' do
|
48
|
+
env = { 'HTTP_HOST' => 'matrix.example.com' }
|
49
|
+
request = Requests::Base.resolve(env)
|
50
|
+
matcher = Subdomain.new(allowed_subdomains: %w{api matrix},
|
51
|
+
request: request)
|
52
|
+
|
53
|
+
expect(matcher.matches?).to be_a TrueClass
|
54
|
+
|
55
|
+
env = { 'HTTP_HOST' => 'api.example.com' }
|
56
|
+
request = Requests::Base.resolve(env)
|
57
|
+
matcher = Subdomain.new(allowed_subdomains: %w{api matrix},
|
58
|
+
request: request)
|
59
|
+
|
60
|
+
expect(matcher.matches?).to be_a TrueClass
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'can match only the api subdomain' do
|
64
|
+
env = { 'HTTP_HOST' => 'matrix.example.com' }
|
65
|
+
request = Requests::Base.resolve(env)
|
66
|
+
matcher = Subdomain.new(allowed_api_subdomains: %w{matrix},
|
67
|
+
request: request)
|
68
|
+
|
69
|
+
expect(matcher.matches_api_subdomain?).to be_a TrueClass
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'matches "api" as an api subdomain by default' do
|
73
|
+
env = { 'HTTP_HOST' => 'api.example.com' }
|
74
|
+
request = Requests::Base.resolve(env)
|
75
|
+
matcher = Subdomain.new(request: request)
|
76
|
+
|
77
|
+
expect(matcher.matches_api_subdomain?).to be_a TrueClass
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,34 +1,39 @@
|
|
1
|
-
require '
|
2
|
-
require 'apill/
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'apill/requests/base'
|
3
|
+
require 'apill/matchers/version'
|
3
4
|
|
4
5
|
module Apill
|
5
6
|
module Matchers
|
6
|
-
describe
|
7
|
+
describe Version do
|
7
8
|
context 'when the version is passed in the accept header' do
|
8
9
|
it 'does not match if the subdomain is API but the requested version does not ' \
|
9
10
|
'equal the version constraint' do
|
10
11
|
|
11
|
-
|
12
|
+
env = {
|
12
13
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
13
14
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=10.0',
|
14
15
|
}
|
16
|
+
request = Requests::Base.resolve(env)
|
15
17
|
|
16
|
-
matcher =
|
18
|
+
matcher = Version.new(request: request,
|
19
|
+
version_constraint: '10.1')
|
17
20
|
|
18
|
-
expect(matcher
|
21
|
+
expect(matcher).not_to be_matches
|
19
22
|
end
|
20
23
|
|
21
24
|
it 'does match if the subdomain is API and the requested version equals the ' \
|
22
25
|
'version constraint' do
|
23
26
|
|
24
|
-
|
27
|
+
env = {
|
25
28
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
26
29
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=10.0',
|
27
30
|
}
|
31
|
+
request = Requests::Base.resolve(env)
|
28
32
|
|
29
|
-
matcher =
|
33
|
+
matcher = Version.new(request: request,
|
34
|
+
version_constraint: '10.0')
|
30
35
|
|
31
|
-
expect(matcher
|
36
|
+
expect(matcher).to be_matches
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -36,43 +41,49 @@ describe VersionMatcher do
|
|
36
41
|
it 'does not match if the subdomain is API but the requested version does not ' \
|
37
42
|
'equal the version constraint' do
|
38
43
|
|
39
|
-
|
44
|
+
env = {
|
40
45
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
41
46
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion',
|
42
47
|
}
|
48
|
+
request = Requests::Base.resolve(env)
|
43
49
|
|
44
|
-
matcher =
|
45
|
-
|
50
|
+
matcher = Version.new(request: request,
|
51
|
+
version_constraint: '10.1',
|
52
|
+
default_version: '10.0')
|
46
53
|
|
47
|
-
expect(matcher
|
54
|
+
expect(matcher).not_to be_matches
|
48
55
|
end
|
49
56
|
|
50
57
|
it 'does match if the subdomain is API and the requested version equals the ' \
|
51
58
|
'version constraint' do
|
52
59
|
|
53
|
-
|
60
|
+
env = {
|
54
61
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
55
62
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion',
|
56
63
|
}
|
64
|
+
request = Requests::Base.resolve(env)
|
57
65
|
|
58
|
-
matcher =
|
59
|
-
|
66
|
+
matcher = Version.new(request: request,
|
67
|
+
version_constraint: '10.0',
|
68
|
+
default_version: '10.0')
|
60
69
|
|
61
|
-
expect(matcher
|
70
|
+
expect(matcher).to be_matches
|
62
71
|
end
|
63
72
|
end
|
64
73
|
|
65
74
|
it 'matches the default version in the configuration if none is passed in' do
|
66
75
|
Apill.configuration.default_api_version = '100.0'
|
67
76
|
|
68
|
-
|
77
|
+
env = {
|
69
78
|
'HTTP_X_APPLICATION_NAME' => 'matrix',
|
70
79
|
'HTTP_ACCEPT' => 'application/vnd.matrix+zion',
|
71
80
|
}
|
81
|
+
request = Requests::Base.resolve(env)
|
72
82
|
|
73
|
-
matcher =
|
83
|
+
matcher = Version.new(request: request,
|
84
|
+
version_constraint: '100.0')
|
74
85
|
|
75
|
-
expect(matcher
|
86
|
+
expect(matcher).to be_matches
|
76
87
|
end
|
77
88
|
end
|
78
89
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'apill/middleware/api_request'
|
3
3
|
|
4
4
|
module Apill
|
@@ -9,10 +9,10 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
9
9
|
before(:each) do
|
10
10
|
HumanError.configuration.url_mappings = {
|
11
11
|
'external_documentation_urls' => {
|
12
|
-
'errors.
|
12
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
13
13
|
},
|
14
14
|
'developer_documentation_urls' => {
|
15
|
-
'errors.
|
15
|
+
'errors.responses.invalid_subdomain' => 'http://example.com/foo',
|
16
16
|
},
|
17
17
|
}
|
18
18
|
|
@@ -61,7 +61,7 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
61
61
|
'documentation' => nil,
|
62
62
|
},
|
63
63
|
'status' => 404,
|
64
|
-
'code' => 'errors.
|
64
|
+
'code' => 'errors.invalid_subdomain',
|
65
65
|
'title' => 'Invalid Subdomain',
|
66
66
|
'detail' => 'The resource you attempted to access is either not authorized ' \
|
67
67
|
'for the authenticated user or does not exist.',
|
@@ -97,7 +97,7 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
97
97
|
'documentation' => nil,
|
98
98
|
},
|
99
99
|
'status' => 400,
|
100
|
-
'code' => 'errors.
|
100
|
+
'code' => 'errors.invalid_api_request',
|
101
101
|
'title' => 'Invalid API Request',
|
102
102
|
'detail' => 'The accept header that you passed in the request cannot be ' \
|
103
103
|
'parsed, please refer to the documentation to verify.',
|
@@ -125,59 +125,57 @@ describe ApiRequest, singletons: HumanError::Configuration do
|
|
125
125
|
expect(response).to eql 'response'
|
126
126
|
end
|
127
127
|
|
128
|
-
it '
|
129
|
-
|
130
|
-
api_request_middleware
|
128
|
+
it 'does allow requests if the subdomain, the accept header and the token are valid' do
|
129
|
+
Apill.configuration.token_private_key = test_private_key
|
130
|
+
api_request_middleware = ApiRequest.new(app)
|
131
131
|
|
132
132
|
request = {
|
133
|
-
'HTTP_HOST'
|
134
|
-
'HTTP_ACCEPT'
|
135
|
-
'
|
136
|
-
|
137
|
-
'hows-the-weather=today-bob',
|
133
|
+
'HTTP_HOST' => 'api.example.com',
|
134
|
+
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
135
|
+
'HTTP_AUTHORIZATION' => "Token #{valid_token}",
|
136
|
+
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
|
138
137
|
}
|
139
138
|
|
140
|
-
|
139
|
+
status, headers, response = api_request_middleware.call(request)
|
141
140
|
|
142
|
-
expect(
|
143
|
-
|
144
|
-
|
141
|
+
expect(status).to eql 200
|
142
|
+
expect(headers).to eql({})
|
143
|
+
expect(response).to eql 'response'
|
145
144
|
end
|
146
145
|
|
147
|
-
it '
|
148
|
-
|
146
|
+
it 'returns the proper response if the token is invalid' do
|
147
|
+
Apill.configuration.token_private_key = test_private_key
|
148
|
+
api_request_middleware = ApiRequest.new(app)
|
149
149
|
|
150
150
|
request = {
|
151
|
-
'
|
152
|
-
'
|
153
|
-
'
|
154
|
-
'QUERY_STRING'
|
151
|
+
'HTTP_HOST' => 'api.example.com',
|
152
|
+
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
153
|
+
'HTTP_AUTHORIZATION' => "Token #{invalid_token}",
|
154
|
+
'QUERY_STRING' => 'accept=application/vnd.matrix+zion;version=1.0.0',
|
155
155
|
}
|
156
156
|
|
157
|
-
|
158
|
-
|
159
|
-
_response = api_request_middleware.call(request)
|
157
|
+
_status, _headers, response = api_request_middleware.call(request)
|
160
158
|
|
161
|
-
expect(
|
162
|
-
with(a_hash_including('CONTENT_TYPE' => 'application/json'))
|
159
|
+
expect(response.first).to include 'errors.invalid_token'
|
163
160
|
end
|
164
161
|
|
165
|
-
it '
|
162
|
+
it 'converts JSON API compliant dasherized query params to underscored' do
|
163
|
+
app = ->(env) { [200, env, 'response'] }
|
166
164
|
api_request_middleware = ApiRequest.new(app)
|
167
165
|
|
168
166
|
request = {
|
169
|
-
'
|
170
|
-
'
|
171
|
-
'
|
172
|
-
|
167
|
+
'HTTP_HOST' => 'api.example.com',
|
168
|
+
'HTTP_ACCEPT' => 'application/vnd.matrix+zion;version=1.0.0',
|
169
|
+
'QUERY_STRING' => 'hello-there=bob-jones&' \
|
170
|
+
'nice-to-meet=you-bob&' \
|
171
|
+
'hows-the-weather=today-bob',
|
173
172
|
}
|
174
173
|
|
175
|
-
|
176
|
-
|
177
|
-
_response = api_request_middleware.call(request)
|
174
|
+
_status, headers, _response = api_request_middleware.call(request)
|
178
175
|
|
179
|
-
expect(
|
180
|
-
|
176
|
+
expect(headers['QUERY_STRING']).to eql 'hello_there=bob-jones&' \
|
177
|
+
'nice_to_meet=you-bob&' \
|
178
|
+
'hows_the_weather=today-bob'
|
181
179
|
end
|
182
180
|
end
|
183
181
|
end
|