Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Breaking] Remove defined versions from gem. #603

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,20 +344,36 @@ result = client.query(SHOP_NAME_QUERY)
result.data.shop.name
```

## Adding additional API versions
We will release a gem update every time we release a new version of the API. Most of the time upgrading the gem will be all you need to do.
## API versions
Default setup for ShopifyApi will be support any string as an api version that is 'unstable' or matches the format 'YYYY-MM'


### Stricter API version usage
You have an option of only using api versions that you define. This can be helpful to ensure you have stopped using older versions that you app no longer wants to rely on.

To make use of this coercion option, add the following to initializing ShopifyApi

If you want access to a newer version without upgrading you can define an api version.
For example if you wanted to add an `ApiVersion` '2022-03', you would add the following to the initialization of your application:
```ruby
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2022-03'))
coercer = ShopifyAPI::VersionCoercers::DefinedOnly.new
coercer.define_version(ShopifyAPI::ApiVersion::Release.new('2019-07')
coercer.define_version(ShopifyAPI::ApiVersion::Unstable.new

ShopifyAPI::ApiVersion.coercer = coercer
```
Once you have done that you can now set this version in a Sesssion like this:

Once you have done that, any use of an undefined version will raise a `ShopifyAPI::VersionCoercers::UnknownVersion` error.

```ruby
ShopifyAPI::Session.new(domain: domain, token: token, api_version: '2022-03')
ShopifyAPI::Session.new(domain: domain, token: token, api_version: '2019-04')
# ShopifyAPI::VersionCoercers::UnknownVersion
```

Defined version will work the same as the default setup.

```ruby
ShopifyAPI::Session.new(domain: domain, token: token, api_version: '2019-07')
ShopifyAPI::Session.new(domain: domain, token: token, api_version: 'stable')
```

## Threadsafety

Expand Down
7 changes: 4 additions & 3 deletions lib/shopify_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
require 'base64'
require 'active_resource/detailed_log_subscriber'
require 'shopify_api/limits'
require 'shopify_api/defined_versions'
require 'shopify_api/version_coercers'
require 'shopify_api/version_coercers/base'
require 'shopify_api/version_coercers/defined_only'
require 'shopify_api/version_coercers/generate_release'
require 'shopify_api/api_version'
require 'active_resource/json_errors'
require 'shopify_api/collection'
Expand All @@ -28,5 +31,3 @@ module ShopifyAPI
else
require 'active_resource/connection_ext'
end

ShopifyAPI::ApiVersion.define_known_versions
35 changes: 18 additions & 17 deletions lib/shopify_api/api_version.rb
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
# frozen_string_literal: true
module ShopifyAPI
class ApiVersion
class UnknownVersion < StandardError; end
class InvalidVersion < StandardError; end
include Comparable

extend DefinedVersions
def self.__coercer
@coercer ||= VersionCoercers::GenerateRelease.new
end

include Comparable
def self.coercer=(version_coercer)
@coercer = version_coercer
end

def self.coerce_to_version(version_or_name)
return version_or_name if version_or_name.is_a?(ApiVersion)

@versions ||= {}
@versions.fetch(version_or_name.to_s) do
raise UnknownVersion, "#{version_or_name} is not in the defined version set: #{@versions.keys.join(', ')}"
end
__coercer.coerce_to_version(version_or_name)
end

def self.define_version(version)
@versions ||= {}

@versions[version.name] = version
warn(
'[DEPRECATED] ShopifyAPI::ApiVersion.define_version is deprecated ' \
'call define_version on the Coercer you assigned'
)
__coercer.define_version(version)
end

def self.clear_defined_versions
@versions = {}
end

def self.latest_stable_version
@versions.values.select(&:stable?).sort.last
warn(
'[DEPRECATED] ShopifyAPI::ApiVersion.clear_defined_versions is deprecated ' \
'use ShopifyAPI::ApiVersion.versions.clear_defined_versions instead.'
)
__coercer.clear_defined_versions
end

def to_s
Expand Down
11 changes: 0 additions & 11 deletions lib/shopify_api/defined_versions.rb

This file was deleted.

6 changes: 6 additions & 0 deletions lib/shopify_api/version_coercers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true
module ShopifyAPI
module VersionCoercers
class UnknownVersion < StandardError; end
end
end
35 changes: 35 additions & 0 deletions lib/shopify_api/version_coercers/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true
module ShopifyAPI
module VersionCoercers
class Base
def initialize
@versions = {}
end

def coerce_to_version(version_or_name)
return version_or_name if version_or_name.is_a?(ApiVersion)
coerce_from_name(version_or_name.to_s)
end

def define_version(version)
versions[version.name] = version
end

def clear_defined_versions
@versions = {}
end

def known_versions
versions.values
end

protected

attr_reader :versions

def coerce_from_name(name)
raise NotImplementedError
end
end
end
end
14 changes: 14 additions & 0 deletions lib/shopify_api/version_coercers/defined_only.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true
module ShopifyAPI
module VersionCoercers
class DefinedOnly < Base
protected

def coerce_from_name(name)
versions.fetch(name) do
raise UnknownVersion, "#{name} is not in the defined version set: #{versions.keys.join(', ')}"
end
end
end
end
end
34 changes: 34 additions & 0 deletions lib/shopify_api/version_coercers/generate_release.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true
module ShopifyAPI
module VersionCoercers
class GenerateRelease < Base
protected

def coerce_from_name(name)
versions.fetch(name) do
record_new_version(name)
end
end

private

def record_new_version(version_name)
new_version = create_new_version(version_name)
define_version(new_version)
new_version
end

def create_new_version(version_name)
if unstable_version.name == version_name
unstable_version
else
ApiVersion::Release.new(version_name)
end
end

def unstable_version
@unstable_version ||= ShopifyAPI::ApiVersion::Unstable.new
end
end
end
end
60 changes: 14 additions & 46 deletions test/api_version_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
class ApiVersionTest < Test::Unit::TestCase
def teardown
super
ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.define_known_versions
ShopifyAPI::ApiVersion.coercer = ShopifyAPI::VersionCoercers::GenerateRelease.new
end

test "unstable version creates url that start with /admin/api/unstable/" do
Expand All @@ -22,43 +21,18 @@ def teardown
)
end

test "coerce_to_version returns any version object given" do
version = ShopifyAPI::ApiVersion::Unstable.new
assert_same(version, ShopifyAPI::ApiVersion.coerce_to_version(version))
end

test "coerce_to_version converts a known version into a version object" do
versions = [
ShopifyAPI::ApiVersion::Unstable.new,
ShopifyAPI::ApiVersion::Release.new('2019-01'),
]
test "coerce_to_version delgates to declared version coercer" do
fake_version = TestApiVersion.new('from fake coercer')

assert_equal(versions, [
ShopifyAPI::ApiVersion.coerce_to_version('unstable'),
ShopifyAPI::ApiVersion.coerce_to_version('2019-01'),
])
end

test "coerce_to_version raises when coercing a string that doesn't match a known version" do
assert_raises ShopifyAPI::ApiVersion::UnknownVersion do
ShopifyAPI::ApiVersion.coerce_to_version('made up version')
fake_coercer = Class.new do
def coerce_to_version(version_name)
TestApiVersion.new('from fake coercer')
end
end
end

test "additional defined versions will also be coerced" do
versions = [
TestApiVersion.new('my_name'),
TestApiVersion.new('other_name'),
]
ShopifyAPI::ApiVersion.coercer = fake_coercer.new

versions.each do |version|
ShopifyAPI::ApiVersion.define_version(version)
end

assert_equal(versions, [
ShopifyAPI::ApiVersion.coerce_to_version('my_name'),
ShopifyAPI::ApiVersion.coerce_to_version('other_name'),
])
assert_equal(fake_version, ShopifyAPI::ApiVersion.coerce_to_version('anything'))
end

test 'allows a release version with the correct format format to be created' do
Expand Down Expand Up @@ -122,18 +96,12 @@ def teardown
].sort)
end

test 'latest_stable_version will return the version that is newest and stable' do
ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2017-11'))
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2019-11'))
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2039-01'))
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2039-02'))
ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Unstable.new)
def with_defined_only_coercion
ShopifyAPI::ApiVersion.coercer = ShopifyAPI::VersionCoercers::DefinedOnly.new
end

assert_equal(
ShopifyAPI::ApiVersion::Release.new('2039-02'),
ShopifyAPI::ApiVersion.latest_stable_version
)
def with_define_on_unknown_coercion
ShopifyAPI::ApiVersion.coercer = ShopifyAPI::VersionCoercers::GenerateRelease.new
end

class TestApiVersion < ShopifyAPI::ApiVersion
Expand Down
2 changes: 0 additions & 2 deletions test/detailed_log_subscriber_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ def setup
@request_headers = "Headers: {\"Accept\"=>\"application/json\", " \
"#{@ua_header}, \"X-Shopify-Access-Token\"=>\"access_token\"}"

ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2019-01'))

ShopifyAPI::Base.clear_session
session = ShopifyAPI::Session.new(
domain: "https://this-is-my-test-shop.myshopify.com",
Expand Down
5 changes: 1 addition & 4 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ def setup
end
end

ShopifyAPI::ApiVersion.define_version(ShopifyAPI::ApiVersion::Release.new('2019-01'))

ShopifyAPI::Base.clear_session
session = ShopifyAPI::Session.new(
domain: "https://this-is-my-test-shop.myshopify.com",
Expand All @@ -55,8 +53,7 @@ def teardown
ShopifyAPI::Base.password = nil
ShopifyAPI::Base.user = nil

ShopifyAPI::ApiVersion.clear_defined_versions
ShopifyAPI::ApiVersion.define_known_versions
ShopifyAPI::ApiVersion.coercer = ShopifyAPI::VersionCoercers::GenerateRelease.new
end

# Custom Assertions
Expand Down
17 changes: 17 additions & 0 deletions test/version_coercers/base_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'test_helper'
require_relative './interface_test_suite'

class VersionCoercersBaseTest < Test::Unit::TestCase
include VersionCoercersInterfaceTestSuite

def setup
@coercer = ShopifyAPI::VersionCoercers::Base.new
end

test "coerce_to_version calls subclass method to coerce anything that isn't already a version" do
assert_raises NotImplementedError do
@coercer.coerce_to_version('unstable')
end
end
end
Loading