Skip to content

upgrade jsonapi-resources #31

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
32 changes: 14 additions & 18 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PATH
specs:
grape-jsonapi (0.0.2)
grape (>= 1.4.0)
jsonapi-resources (~> 0.9.11)
jsonapi-resources (~> 0.10.7)

GEM
remote: https://rubygems.org/
Expand Down Expand Up @@ -42,30 +42,26 @@ GEM
crass (1.0.6)
diff-lcs (1.4.4)
docile (1.3.2)
dry-configurable (0.11.6)
dry-configurable (0.14.0)
concurrent-ruby (~> 1.0)
dry-core (~> 0.4, >= 0.4.7)
dry-equalizer (~> 0.2)
dry-container (0.7.2)
dry-core (~> 0.6)
dry-container (0.9.0)
concurrent-ruby (~> 1.0)
dry-configurable (~> 0.1, >= 0.1.3)
dry-core (0.4.9)
dry-configurable (~> 0.13, >= 0.13.0)
dry-core (0.7.1)
concurrent-ruby (~> 1.0)
dry-equalizer (0.3.0)
dry-inflector (0.2.0)
dry-logic (1.0.8)
dry-inflector (0.2.1)
dry-logic (1.2.0)
concurrent-ruby (~> 1.0)
dry-core (~> 0.2)
dry-equalizer (~> 0.2)
dry-types (1.4.0)
dry-core (~> 0.5, >= 0.5)
dry-types (1.5.1)
concurrent-ruby (~> 1.0)
dry-container (~> 0.3)
dry-core (~> 0.4, >= 0.4.4)
dry-equalizer (~> 0.3)
dry-core (~> 0.5, >= 0.5)
dry-inflector (~> 0.1, >= 0.1.2)
dry-logic (~> 1.0, >= 1.0.2)
erubi (1.9.0)
grape (1.5.0)
grape (1.6.2)
activesupport
builder
dry-types (>= 1.1)
Expand All @@ -79,7 +75,7 @@ GEM
concurrent-ruby (~> 1.0)
json-schema (2.8.1)
addressable (>= 2.4)
jsonapi-resources (0.9.11)
jsonapi-resources (0.10.7)
activerecord (>= 4.1)
concurrent-ruby
railties (>= 4.1)
Expand Down Expand Up @@ -161,7 +157,7 @@ GEM
rubocop-ast (0.8.0)
parser (>= 2.7.1.5)
ruby-progressbar (1.10.1)
ruby2_keywords (0.0.2)
ruby2_keywords (0.0.5)
simplecov (0.19.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
Expand Down
2 changes: 1 addition & 1 deletion grape-jsonapi.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
end

spec.add_runtime_dependency 'grape', '>= 1.4.0'
spec.add_runtime_dependency 'jsonapi-resources', '~> 0.9.11'
spec.add_runtime_dependency 'jsonapi-resources', '~> 0.10.7'
end
2 changes: 1 addition & 1 deletion lib/grape/jsonapi/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def jsonapi_resource
declare_base_route

# Before generating links for resources while building a response, the jsonapi-resources
# gem verifies whether there are routes to them. If no, a warning intead of a link
# gem verifies whether there are routes to them. If no, a warning instead of a link
# will be outputed. This gem doesn't use route helpers of the jsonapi-resources gem,
# but it adds Grape routes, so a `_routed` flag must be added for every resource
# which routed by Grape.
Expand Down
102 changes: 82 additions & 20 deletions lib/grape/jsonapi/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
module Grape
module JSONAPI
# A collection of helper methods used internally by JSON API endpoints.
# Mainly methods were copied from https://bit.ly/3ygyl5y then adjusted.
module Helpers
include Rendering
include Resources

attr_reader :jsonapi_request

def controller_class
env['api.endpoint'].options[:for]
end
Expand All @@ -26,38 +29,49 @@ def json_request_for(action, options)
action_parameters,
# define a `context` method to pass extra data to resources
context: respond_to?(:context) ? send(:context) : {},
key_formatter: key_formatter,
server_error_callbacks: []
)
end

def process_request(action, options = {})
@json_request = json_request_for(action.to_sym, options)
begin
@jsonapi_request = json_request_for(action, options)

if @json_request.errors.empty?
results = operation_dispatcher.process(@json_request.operations)
render_results results
else
render_errors(@json_request.errors)
setup_response_document
execute_request
rescue StandardError => e
handle_exceptions(e)
end
rescue ::JSONAPI::Exceptions::Error => e
render_errors(e.errors)
end

def operation_dispatcher
::JSONAPI::OperationDispatcher.new(
transaction: transaction_block,
rollback: rollback_action,
server_error_callbacks: []
)
render_results
end

def transaction_block
->(&block) { ActiveRecord::Base.transaction { block.yield } }
end
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def execute_request
process_operations(jsonapi_request.transactional?) do
jsonapi_request.each(response_document) do |op|
op.options[:serializer] = resource_serializer_klass.new(
op.resource_klass,
include_directives: op.options[:include_directives],
fields: op.options[:fields],
base_url: base_url,
key_formatter: key_formatter,
route_formatter: route_formatter,
serialization_options: {},
controller: self
)
op.options[:cache_serializer_output] = !::JSONAPI.configuration.resource_cache.nil?

def rollback_action
-> { fail ActiveRecord::Rollback }
process_operation(op)
end

fail ActiveRecord::Rollback if response_document.has_errors?
end
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize

def forbidden_operation
render_errors [::JSONAPI::Error.new(
Expand All @@ -67,6 +81,54 @@ def forbidden_operation
detail: I18n.t('jsonapi.errors.forbidden_operation.detail')
)]
end

def process_operations(transactional, &block)
if transactional
ActiveRecord::Base.transaction(&block)
else
begin
block.call
rescue ActiveRecord::Rollback
# Can't rollback without transaction, so just ignore it
end
end
end

def process_operation(operation)
result = operation.process
response_document.add_result(result, operation)
end

private

# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def handle_exceptions(exeption)
case exeption
when ::JSONAPI::Exceptions::Error
errors = exeption.errors
when ActionController::ParameterMissing
errors = ::JSONAPI::Exceptions::ParameterMissing.new(exeption.param).errors
else
fail exeption if ::JSONAPI.configuration.exception_class_whitelisted?(exeption)

# Store exception for other middlewares
request.env['action_dispatch.exception'] ||= exeption

internal_server_error = ::JSONAPI::Exceptions::InternalServerError.new(exeption)

Rails.logger.error do
"Internal Server Error: #{exeption.message} #{exeption.backtrace.join("\n")}"
end

errors = internal_server_error.errors
end

response_document.add_result(::JSONAPI::ErrorsOperationResult.new(errors[0].status, errors),
nil)
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
end
end
end
4 changes: 2 additions & 2 deletions lib/grape/jsonapi/relationships.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ def declare_related_resource(name, relationship, _options)
define_related_resource_helpers(relationship)

if to_many?(relationship)
get { process_request(:get_related_resources, related_params) }
get { process_request(:index_related_resources, related_params) }
else
get { process_request(:get_related_resource, related_params) }
get { process_request(:show_related_resource, related_params) }
end
end
end
Expand Down
37 changes: 22 additions & 15 deletions lib/grape/jsonapi/rendering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,42 @@ module JSONAPI
module Rendering
include Resources

attr_reader :response_document

def render_errors(errors)
operation_results = ::JSONAPI::OperationResults.new
setup_response_document

result = ::JSONAPI::ErrorsOperationResult.new(
errors.first.status, errors
)

operation_results.add_result(result)
response_document.add_result(result, nil)

render_results operation_results
render_results
end

def render_results(operation_results)
response_doc = create_response_document(operation_results)

response_status(response_doc)
response_doc.status == :no_content ? '' : response_doc.contents
def render_results
response_status
response_document.status == 204 ? '' : response_document.contents
end

private

def create_response_document(operation_results)
def create_response_document
::JSONAPI::ResponseDocument.new(
operation_results,
operation_results.has_errors? ? nil : resource_serializer,
key_formatter: key_formatter,
base_meta: base_meta,
base_links: base_links,
request: @json_request
base_links: base_response_links,
request: respond_to?(:request) ? request : nil
)
end

def response_status(response_doc)
status_code = response_doc.status
def setup_response_document
@response_document = create_response_document
end

def response_status
status_code = response_document.status
status_code = status_code.to_i if status_code.is_a? String
status status_code
end
Expand All @@ -47,6 +50,10 @@ def base_links
{}
end

def base_response_links
{}
end

def base_meta
return {} unless defined? @json_request

Expand Down
4 changes: 2 additions & 2 deletions lib/grape/jsonapi/resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def controller_name
end

def resource_class
::JSONAPI::Resource.resource_for controller_name
::JSONAPI::Resource.resource_klass_for controller_name
end

def resource_name
Expand All @@ -26,7 +26,7 @@ def resource_module_name
end

def related_resource_for(relationship)
::JSONAPI::Resource.resource_for(
::JSONAPI::Resource.resource_klass_for(
"#{resource_module_name}/#{relationship.class_name}".underscore
)
end
Expand Down
4 changes: 3 additions & 1 deletion spec/fixtures/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ def title=(title)
return values
},
apply: lambda { |records, value, _options|
records.where('id IN (?)', value)
records.where('posts.id IN (?)', value)
}

filter :search,
Expand Down Expand Up @@ -1148,6 +1148,7 @@ class BoatResource < BoatResource; end

module Api
module V2
class AuthorResource < PreferencesResource; end
class PreferencesResource < PreferencesResource; end
class PersonResource < PersonResource; end
class PostResource < PostResource; end
Expand Down Expand Up @@ -1257,6 +1258,7 @@ class PreferencesResource < PreferencesResource; end

module Api
module V4
class AuthorResource < PreferencesResource; end
class PostResource < PostResource; end
class PersonResource < PersonResource; end
class ExpenseEntryResource < ExpenseEntryResource; end
Expand Down