Skip to content

Commit a17c1f5

Browse files
committed
add coercion modes for apiversion validation
1 parent 6b0544c commit a17c1f5

5 files changed

+74
-38
lines changed

lib/shopify_api.rb

-2
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,3 @@ module ShopifyAPI
2727
else
2828
require 'active_resource/connection_ext'
2929
end
30-
31-
ShopifyAPI::ApiVersion.define_known_versions

lib/shopify_api/api_version.rb

+36-14
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,63 @@ class InvalidVersion < StandardError; end
1212
UNSTABLE_HANDLE = 'unstable'
1313
UNSTABLE_AS_DATE = Time.utc(3000, 1, 1)
1414
API_PREFIX = '/admin/api/'
15+
COERSION_MODES = [:predefined_only, :define_on_unknown].freeze
1516

1617
class << self
1718
attr_reader :versions
1819

20+
def coercion_mode
21+
@coercion_mode ||= :define_on_unknown
22+
end
23+
24+
def coercion_mode=(mode)
25+
raise ArgumentError, "Mode must be one of #{COERSION_MODES}" unless COERSION_MODES.include?(mode)
26+
sanitize_known_versions if mode == :predefined_only
27+
@coercion_mode = mode
28+
end
29+
1930
def coerce_to_version(version_or_handle)
2031
return version_or_handle if version_or_handle.is_a?(ApiVersion)
21-
if @versions.nil?
22-
warn "[API VERSION WARNING] Known API Version set is empty. Initializing unvalidated version from handle."
23-
return ApiVersion.new(handle: version_or_handle)
24-
end
25-
26-
@versions[version_or_handle.to_s].tap do |api_version|
27-
unless api_version
28-
raise ApiVersion::UnknownVersion, "UnknownVersion API version specified, `#{version_or_handle}`. \n Versions available: #{@versions.keys}"
32+
handle = version_or_handle.to_s
33+
34+
@versions ||= {}
35+
@versions.fetch(handle) do
36+
if @coercion_mode == :predefined_only
37+
error_msg = if @versions.empty?
38+
"No versions defined. You must call `ApiVersion.define_known_versions` first."
39+
else
40+
"`#{handle}` is not in the defined version set. Available versions: #{@versions.keys}"
41+
end
42+
raise UnknownVersion, "ApiVersion.coercion_mode is set to `:predefined_only`. #{error_msg}"
43+
else
44+
@versions[handle] = ApiVersion.new(handle: version_or_handle)
2945
end
3046
end
3147
end
3248

3349
def define_known_versions
3450
@versions = Meta.admin_versions.map { |version| [version.handle, version] }.to_h
35-
rescue ActiveResource::ConnectionError => e
36-
warn "[API VERSION WARNING] Could not fetch Admin API versions."
37-
warn "[API VERSION WARNING] #{e.message}"
38-
@versions = nil
3951
end
4052

4153
def clear_defined_versions
42-
@versions = nil
54+
@versions = {}
4355
end
4456

4557
def latest_stable_version
4658
warn(
4759
'[DEPRECATED] ShopifyAPI::ApiVersion.latest_stable_version is deprecated and will be removed in a future version.'
4860
)
49-
@versions.values.find(&:latest_supported?)
61+
versions.values.find(&:latest_supported?)
62+
end
63+
64+
private
65+
66+
def sanitize_known_versions
67+
return if @versions.nil?
68+
@versions = @versions.keys.map do |handle|
69+
next unless @versions[handle].persisted?
70+
[handle, @versions[handle]]
71+
end.compact.to_h
5072
end
5173
end
5274

test/api_version_test.rb

+25-9
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,33 @@ class ApiVersionTest < Test::Unit::TestCase
1919
])
2020
end
2121

22-
test "coerce_to_version raises when coercing a string that doesn't match a known version" do
23-
refute ShopifyAPI::ApiVersion.versions.nil?
24-
assert_raises ShopifyAPI::ApiVersion::UnknownVersion do
22+
test "coerce_to_version removes unpersisted versions from version set if mode is set to :predefined_only" do
23+
ShopifyAPI::ApiVersion.coercion_mode = :define_on_unknown
24+
assert ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
25+
assert_equal 5, ShopifyAPI::ApiVersion.versions.size
26+
27+
ShopifyAPI::ApiVersion.coerce_to_version('2019-30')
28+
refute ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
29+
assert_equal 6, ShopifyAPI::ApiVersion.versions.size
30+
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
31+
32+
assert ShopifyAPI::ApiVersion.versions.values.all?(&:persisted?)
33+
assert_equal 5, ShopifyAPI::ApiVersion.versions.size
34+
end
35+
36+
test "coerce_to_version does not raise when coercing a string if no versions are defined when coercion_mode is :define_on_unknown" do
37+
ShopifyAPI::ApiVersion.clear_defined_versions
38+
ShopifyAPI::ApiVersion.coercion_mode = :define_on_unknown
39+
assert_equal :define_on_unknown, ShopifyAPI::ApiVersion.coercion_mode
40+
assert_nothing_raised do
2541
ShopifyAPI::ApiVersion.coerce_to_version('made up version')
2642
end
2743
end
2844

29-
test "coerce_to_version does not raise when coercing a string if no versions are defined" do
30-
ShopifyAPI::ApiVersion.clear_defined_versions
31-
assert_nil ShopifyAPI::ApiVersion.versions
32-
assert_nothing_raised do
45+
test "coerce_to_version does raise when coercing a string if no versions are defined when coercion_mode is :predefined_only" do
46+
refute ShopifyAPI::ApiVersion.versions['made up version']
47+
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
48+
assert_raises ShopifyAPI::ApiVersion::UnknownVersion do
3349
ShopifyAPI::ApiVersion.coerce_to_version('made up version')
3450
end
3551
end
@@ -77,8 +93,8 @@ class ApiVersionTest < Test::Unit::TestCase
7793
"2019-01" => ShopifyAPI::ApiVersion.new(handle: '2019-01', supported: true, latest_supported: false),
7894
"2019-04" => ShopifyAPI::ApiVersion.new(handle: '2019-04', supported: true, latest_supported: false),
7995
"2019-07" => ShopifyAPI::ApiVersion.new(handle: '2019-07', supported: true, latest_supported: true),
80-
"2019-10" => ShopifyAPI::ApiVersion.new(handle: '2019-10', supported: true, latest_supported: false),
81-
"unstable" => ShopifyAPI::ApiVersion.new(handle: 'unstable', supported: true, latest_supported: false),
96+
"2019-10" => ShopifyAPI::ApiVersion.new(handle: '2019-10', supported: false, latest_supported: false),
97+
"unstable" => ShopifyAPI::ApiVersion.new(handle: 'unstable', supported: false, latest_supported: false),
8298
}
8399
)
84100

test/detailed_log_subscriber_test.rb

+12-5
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ def setup
1414
@request_headers = "Headers: {\"Accept\"=>\"application/json\", " \
1515
"#{@ua_header}, \"X-Shopify-Access-Token\"=>\"access_token\"}"
1616

17-
fake("api_versions",
17+
ShopifyAPI::Base.clear_session
18+
fake("apis",
19+
url: "https://app.shopify.com/services/apis.json",
1820
method: :get,
1921
status: 200,
20-
api_version: ShopifyAPI::ApiVersion.new(handle: :unstable),
21-
body: load_fixture('api_versions'))
22-
23-
ShopifyAPI::Base.clear_session
22+
api_version: :stub,
23+
body: load_fixture('apis'))
24+
ShopifyAPI::ApiVersion.define_known_versions
2425
session = ShopifyAPI::Session.new(
2526
domain: "https://this-is-my-test-shop.myshopify.com",
2627
token: "access_token",
@@ -33,6 +34,12 @@ def setup
3334
ActiveResource::DetailedLogSubscriber.attach_to :active_resource_detailed
3435
end
3536

37+
def teardown
38+
super
39+
ShopifyAPI::ApiVersion.clear_defined_versions
40+
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
41+
end
42+
3643
def set_logger(logger)
3744
ActiveResource::Base.logger = logger
3845
end

test/test_helper.rb

+1-8
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@
88
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
99

1010
FakeWeb.allow_net_connect = false
11-
FakeWeb.register_uri(
12-
:get,
13-
"https://app.shopify.com/services/apis.json",
14-
status: 200,
15-
body: File.read(File.dirname(__FILE__) + "/fixtures/apis.json"),
16-
content_type: "text/json"
17-
)
1811

1912
require 'shopify_api'
2013

@@ -72,8 +65,8 @@ def teardown
7265
ShopifyAPI::Base.site = nil
7366
ShopifyAPI::Base.password = nil
7467
ShopifyAPI::Base.user = nil
75-
7668
ShopifyAPI::ApiVersion.clear_defined_versions
69+
ShopifyAPI::ApiVersion.coercion_mode = :predefined_only
7770
end
7871

7972
# Custom Assertions

0 commit comments

Comments
 (0)