Skip to content

Commit

Permalink
add status_handlers to JsonApiClient::Resource.connection_options
Browse files Browse the repository at this point in the history
it allows to override status handling
  • Loading branch information
senid231 committed Jan 11, 2019
1 parent f2a20e2 commit 3901272
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 2 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,27 @@ module MyApi
end
```
##### Custom status handler
You can change handling of response status using `connection_options`. For example you can override 400 status handling.
By default it raises `JsonApiClient::Errors::ClientError` but you can skip exception if you want to process errors from the server.
You need to provide a `proc` which should call `throw(:handled)` default handler for this status should be skipped.
```ruby
MyApi::Base.connection_options[:status_handlers] = ->(code, _env) do
throw(:handled) if code == 400
end

module MyApi
class User < Base
# will use the customized status_handlers
end
end

user = MyApi::User.create(name: 'foo')
# server responds with { errors: [ { detail: 'bad request' } ] }
user.errors.messages # { base: ['bad request'] }
```

##### Specifying an HTTP Proxy

All resources have a class method ```connection_options``` used to pass options to the JsonApiClient::Connection initializer.
Expand Down
3 changes: 2 additions & 1 deletion lib/json_api_client/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ def initialize(options = {})
site = options.fetch(:site)
connection_options = options.slice(:proxy, :ssl, :request, :headers, :params)
adapter_options = Array(options.fetch(:adapter, Faraday.default_adapter))
status_middleware_options = { custom_handlers: options[:status_handlers] }
@faraday = Faraday.new(site, connection_options) do |builder|
builder.request :json
builder.use Middleware::JsonRequest
builder.use Middleware::Status
builder.use Middleware::Status, status_middleware_options
builder.use Middleware::ParseJson
builder.adapter(*adapter_options)
end
Expand Down
22 changes: 21 additions & 1 deletion lib/json_api_client/middleware/status.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
module JsonApiClient
module Middleware
class Status < Faraday::Middleware
def initialize(app, options)
super(app)
@options = options
end

def call(environment)
@app.call(environment).on_complete do |env|
handle_status(env[:status], env)
Expand All @@ -15,9 +20,24 @@ def call(environment)
raise Errors::ConnectionError.new environment, e.to_s
end

protected
private

def custom_handlers
Array.wrap @options[:custom_handlers]
end

def handled_by_custom?(code, env)
result = catch(:handled) do
custom_handlers.each { |handler| handler.call(code, env) }
true
end
# throw(:handled) was called
result.nil?
end

def handle_status(code, env)
return if handled_by_custom?(code, env)

case code
when 200..399
when 401
Expand Down
6 changes: 6 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class Comment < TestResource
class User < TestResource
end

class UserAllowedBadRequest < TestResource
self.connection_options = {
status_handlers: ->(code, _env) { throw(:handled) if code == 400 }
}
end

class UserPreference < TestResource
self.primary_key = :user_id
end
Expand Down
51 changes: 51 additions & 0 deletions test/unit/status_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,57 @@ def test_server_responding_with_408_status
end
end

def test_server_responding_with_400_status
stub_request(:get, "http://example.com/users/1")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
meta: {
status: 400,
message: "Bad Request"
}
}.to_json)

assert_raises JsonApiClient::Errors::ClientError do
User.find(1)
end
end

def test_server_responding_with_400_status_in_meta_with_custom_status_handler
stub_request(:get, "http://example.com/user_allowed_bad_requests/1")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
meta: {
status: 400,
message: "Bad Request"
}
}.to_json)

UserAllowedBadRequest.find(1)
end

def test_server_responding_with_400_status_with_custom_status_handler
stub_request(:post, "http://example.com/user_allowed_bad_requests")
.with(headers: { content_type: 'application/vnd.api+json', accept: 'application/vnd.api+json' }, body: {
data: {
type: 'user_allowed_bad_requests',
attributes: {
name: 'foo'
}
}
}.to_json)
.to_return(status: 400, headers: { content_type: "application/vnd.api+json" }, body: {
errors: [
{
status: '400',
detail: 'Bad Request'
}
]
}.to_json)

user = UserAllowedBadRequest.create(name: 'foo')
refute user.persisted?
expected_errors = { base: ['Bad Request'] }
assert_equal expected_errors, user.errors.messages
end

def test_server_responding_with_422_status
stub_request(:get, "http://example.com/users/1")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
Expand Down

0 comments on commit 3901272

Please sign in to comment.