diff --git a/CHANGELOG.md b/CHANGELOG.md index f907bbb..a082a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### 0.9.2 (Next) +* [#150](https://github.com/codegram/hyperclient/pull/150): Add better support for globalid and active job - [@yuki24](https://github.com/yuki24). * Your contribution here. ### 0.9.1 (2019/08/25) diff --git a/hyperclient.gemspec b/hyperclient.gemspec index bd95c5c..b261d10 100644 --- a/hyperclient.gemspec +++ b/hyperclient.gemspec @@ -19,4 +19,6 @@ Gem::Specification.new do |gem| gem.add_dependency 'faraday_hal_middleware' gem.add_dependency 'faraday_middleware' gem.add_dependency 'net-http-digest_auth' + + gem.add_development_dependency 'globalid' end diff --git a/lib/hyperclient.rb b/lib/hyperclient.rb index 68e83f3..f6b10e2 100644 --- a/lib/hyperclient.rb +++ b/lib/hyperclient.rb @@ -7,16 +7,23 @@ require 'hyperclient/resource' require 'hyperclient/resource_collection' require 'hyperclient/version' +require 'hyperclient/railtie' if defined?(Rails) # Public: Hyperclient namespace. # module Hyperclient + URL_TO_ENDPOINT_MAPPING = { } + # Public: Convenience method to create new EntryPoints. # # url - A String with the url of the API. # # Returns a Hyperclient::EntryPoint def self.new(url, &block) - Hyperclient::EntryPoint.new(url, &block) + URL_TO_ENDPOINT_MAPPING[url] = Hyperclient::EntryPoint.new(url, &block) + end + + def self.lookup_entry_point(uri) + URL_TO_ENDPOINT_MAPPING[uri] || raise(ArgumentError, "Entry point not registered for #{uri}") end end diff --git a/lib/hyperclient/global_id.rb b/lib/hyperclient/global_id.rb new file mode 100644 index 0000000..d817351 --- /dev/null +++ b/lib/hyperclient/global_id.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'delegate' +require 'globalid' + +module Hyperclient + module GlobalId + class Locator + def locate(gid) + Hyperclient + .lookup_entry_point(gid.params['endpoint']) + .public_send(gid.params['key'], gid.params.except('app', 'endpoint', 'key')) + end + end + + class Serializable < SimpleDelegator + def id + _url + end + end + + private_constant :Serializable + + def self.app_name + "#{GlobalID.app}-hyperclient" + end + + def self.setup! + ::Hyperclient::Link.include ::GlobalID::Identification + ::Hyperclient::Link.prepend ::Hyperclient::GlobalId + + ::GlobalID::Locator.use app_name, ::Hyperclient::GlobalId::Locator.new + end + + def to_global_id(options = {}) + GlobalID.create(Serializable.new(self), default_global_id_options.merge(options)) + end + alias to_gid to_global_id + + def to_signed_global_id(options = {}) + SignedGlobalID.create(Serializable.new(self), default_global_id_options.merge(options)) + end + alias to_sgid to_signed_global_id + + private + + def default_global_id_options + { + app: ::Hyperclient::GlobalId.app_name, + endpoint: @entry_point._url, + key: @key, + **@uri_variables || {}, + } + end + end +end \ No newline at end of file diff --git a/lib/hyperclient/railtie.rb b/lib/hyperclient/railtie.rb new file mode 100644 index 0000000..3470b92 --- /dev/null +++ b/lib/hyperclient/railtie.rb @@ -0,0 +1,11 @@ +module Hyperclient + class Railtie < ::Rails::Railtie #:nodoc: + initializer 'hyperclient.client.attach_log_subscriber' do + ActiveSupport.on_load(:active_job) do + require 'hyperclient/global_id' + + ::Hyperclient::GlobalId.setup! + end + end + end +end diff --git a/test/hyperclient/link_test.rb b/test/hyperclient/link_test.rb index 47a3785..ef93d2f 100644 --- a/test/hyperclient/link_test.rb +++ b/test/hyperclient/link_test.rb @@ -1,5 +1,6 @@ require_relative '../test_helper' require 'hyperclient' +require 'hyperclient/global_id' module Hyperclient describe Link do @@ -350,5 +351,33 @@ module Hyperclient end end end + + describe 'GlobalId Support' do + describe '#to_global_id' do + before do + Hyperclient::GlobalId.setup! + Hyperclient::URL_TO_ENDPOINT_MAPPING[entry_point._url] = entry_point + end + + it "serializes the object with entry point, key and uri_variables if present" do + link = Link.new('key', { 'href' => "http://api.example.org/key" }, entry_point) + + stub_request(entry_point.connection) do |stub| + stub.get('http://api.example.org/') { [200, {}, { '_links' => { 'key' => { 'href' => 'http://api.example.org/key' } } }] } + end + + actual = GlobalID.find(link.to_global_id) + + actual._url.must_equal(link._url) + end + + it "raises an exception when the hypermedia URL is missing" do + link_without_href = Link.new('key', { }, entry_point) + message = "Unable to create a Global ID for Hyperclient::GlobalId::Serializable without a model id." + + -> { link_without_href.to_global_id }.must_raise(URI::GID::MissingModelIdError, message) + end + end + end end -end +end \ No newline at end of file