From 2e42ba81baf9a70bce5b165ee9d524f9d335f320 Mon Sep 17 00:00:00 2001 From: Jens Balvig Date: Tue, 18 Oct 2022 14:55:41 +0200 Subject: [PATCH] configure mapping outside Faraday --- lib/spyke/http.rb | 9 +++++++- lib/spyke/result.rb | 29 ++++++++++------------- test/orm_test.rb | 8 +++---- test/support/fixtures.rb | 50 +++++++++++++++------------------------- test/support/webmock.rb | 3 ++- 5 files changed, 45 insertions(+), 54 deletions(-) diff --git a/lib/spyke/http.rb b/lib/spyke/http.rb index c3ff901..3079003 100644 --- a/lib/spyke/http.rb +++ b/lib/spyke/http.rb @@ -10,9 +10,16 @@ module Http included do class_attribute :connection, instance_accessor: false + + class_attribute :json_mapping + self.json_mapping = { data_key: :data, metadata_key: :metadata, errors_key: :errors } end module ClassMethods + def spyke_json_mapping(map) + self.json_mapping.merge!(map) + end + METHODS.each do |method| define_method(method) do new_instance_or_collection_from_result scoped_request(method) @@ -23,7 +30,7 @@ def request(method, path, params = {}) ActiveSupport::Notifications.instrument('request.spyke', method: method) do |payload| response = send_request(method, path, params) payload[:url], payload[:status] = response.env.url, response.status - Result.new_from_response(response) + Result.new_from_response_body(response.body, **json_mapping) end end diff --git a/lib/spyke/result.rb b/lib/spyke/result.rb index 1e02160..1de8f55 100644 --- a/lib/spyke/result.rb +++ b/lib/spyke/result.rb @@ -1,25 +1,20 @@ module Spyke class Result - attr_reader :body + attr_reader :data, :metadata, :errors - def self.new_from_response(response) - new(response.body) + def self.new_from_response_body(body, data_key:, metadata_key:, errors_key:) + body = HashWithIndifferentAccess.new(body.presence) + new( + data: body[data_key], + metadata: body[metadata_key], + errors: body[errors_key] + ) end - def initialize(body) - @body = HashWithIndifferentAccess.new(body) - end - - def data - body[:data] - end - - def metadata - body[:metadata] || {} - end - - def errors - body[:errors] || [] + def initialize(data:, metadata: nil, errors: nil) + @data = data + @metadata = metadata || {} + @errors = errors || [] end end end diff --git a/test/orm_test.rb b/test/orm_test.rb index 290d9b3..e5eb25e 100644 --- a/test/orm_test.rb +++ b/test/orm_test.rb @@ -26,7 +26,7 @@ def test_reload end def test_404 - stub_request(:get, 'http://sushi.com/recipes/1').to_return(status: 404, body: { message: 'Not found' }.to_json) + stub_request(:get, 'http://sushi.com/recipes/1').to_return_json({ body: { message: 'Not found' } }, status: 404) assert_raises(ResourceNotFound) { Recipe.find(1) } assert_raises(ResourceNotFound) { Recipe.find(nil) } @@ -185,14 +185,14 @@ def test_scoped_destroy_class_method_without_param end def test_relative_uris - previous = Spyke::Base.connection.url_prefix - Spyke::Base.connection.url_prefix = 'http://sushi.com/api/v2/' + previous = Api.connection.url_prefix + Api.connection.url_prefix = 'http://sushi.com/api/v2/' endpoint = stub_request(:get, 'http://sushi.com/api/v2/recipes') Recipe.all.to_a assert_requested endpoint - Spyke::Base.connection.url_prefix = previous + Api.connection.url_prefix = previous end def test_custom_primary_key_on_collection diff --git a/test/support/fixtures.rb b/test/support/fixtures.rb index 55a5a2d..523c1f0 100644 --- a/test/support/fixtures.rb +++ b/test/support/fixtures.rb @@ -1,28 +1,16 @@ -require 'multi_json' - -# Dummy api -class JSONParser < Faraday::Middleware - def on_complete(env) - json = MultiJson.load(env.body, symbolize_keys: true) - env.body = { - data: json[:result], - metadata: json[:metadata], - errors: json[:errors] - } - rescue MultiJson::ParseError => exception - env.body = { errors: { base: [ error: exception.message ] } } +class Api < Spyke::Base + self.connection = Faraday.new(url: 'http://sushi.com') do |faraday| + faraday.request :multipart + faraday.request :json + faraday.response :json + faraday.adapter Faraday.default_adapter end -end -Spyke::Base.connection = Faraday.new(url: 'http://sushi.com') do |faraday| - faraday.request :multipart - faraday.request :json - faraday.use JSONParser - faraday.adapter Faraday.default_adapter + spyke_json_mapping data_key: :result end # Test classes -class Recipe < Spyke::Base +class Recipe < Api has_many :groups has_many :gallery_images, class_name: 'Image' has_one :image @@ -62,7 +50,7 @@ def before_update_callback; end def before_save_callback; end end -class Image < Spyke::Base +class Image < Api method_for :create, :put attributes :description, :caption end @@ -80,7 +68,7 @@ class RecipeImage < Image include_root_in_json false end -class Group < Spyke::Base +class Group < Api has_many :ingredients, uri: nil has_many :featured_ingredients, uri: 'featured_ingredients?filter[group_id]=:group_id', class_name: "Ingredient" accepts_nested_attributes_for :ingredients @@ -93,20 +81,20 @@ def self.build_default end end -class Ingredient < Spyke::Base +class Ingredient < Api uri 'recipes/:recipe_id/ingredients/(:id)' end -class User < Spyke::Base +class User < Api self.primary_key = :uuid has_many :recipes end -class Photo < Spyke::Base +class Photo < Api uri 'images/photos/(:id)' end -class Comment < Spyke::Base +class Comment < Api belongs_to :user has_many :users scope :approved, -> { where(comment_approved: true) } @@ -115,7 +103,7 @@ class Comment < Spyke::Base class OtherApi < Spyke::Base self.connection = Faraday.new(url: 'http://sashimi.com') do |faraday| - faraday.use JSONParser + faraday.response :json faraday.adapter Faraday.default_adapter end end @@ -145,7 +133,7 @@ def suggestions end module Cookbook - class Tip < Spyke::Base + class Tip < Api uri 'tips/(:id)' has_many :likes, class_name: 'Cookbook::Like' has_many :favorites @@ -153,14 +141,14 @@ class Tip < Spyke::Base has_many :photos, class_name: 'Photo' end - class Like < Spyke::Base + class Like < Api belongs_to :tip end - class Favorite < Spyke::Base + class Favorite < Api end - class Photo < Spyke::Base + class Photo < Api include_root_in_json :foto end end diff --git a/test/support/webmock.rb b/test/support/webmock.rb index 2ccb8d4..e766bb7 100644 --- a/test/support/webmock.rb +++ b/test/support/webmock.rb @@ -2,7 +2,8 @@ class WebMock::RequestStub def to_return_json(hash, options = {}) - options[:body] = MultiJson.dump(hash) + options[:body] = hash.to_json + options[:headers] = { content_type: 'application/json' } to_return(options) end end