Skip to content

Commit

Permalink
Allow to pass response handling to parent scopes
Browse files Browse the repository at this point in the history
For example to allow to handle specific cases in operation handlers
and common cases – in parent scopes.
  • Loading branch information
Envek committed Dec 13, 2017
1 parent 977cc52 commit f6abe17
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
25 changes: 25 additions & 0 deletions docs/helpers/response.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ response 400, 422 do |_status, *|
end
```

In case if you want to implement hierarchical processing of errors from more specific to certain operations or scopes to common errors of whole API, you can call `super!` method from response handler when you want to delegate handling to parent scope:

```ruby
class YourAPI < Evil::Client
scope :entities do
operation :create do
response(409) do |_, _, body|
data = JSON.parse(body.first)
case data.dig("errors", 0, "errorId")
when 35021
raise YourAPI::AlreadyExists, data.dig("errors", 0, "message")
else
super!
end
end
end
end

response(409) do |_, _, body|
data = JSON.parse(body.first)
raise EbayAPI::Error, data.dig("errors", 0, "message")
end
end
```

When you use client-specific [middleware], the `response` block will receive the result already processed by the whole middleware stack. The helper will serve a final step of its handling. Its result wouldn't be processed further in any way.

If a remote API will respond with a status, not defined for the operation, the `Evil::Client::ResponseError` will be risen. The exception carries both the response, and all its parts (status, headers, and body).
Expand Down
19 changes: 14 additions & 5 deletions lib/evil/client/resolver/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,30 @@ class Evil::Client
class Resolver::Response < Resolver
private

PROCESSING_DONE = Object.new
SKIP_RESPONSE = Object.new

def initialize(schema, settings, response)
@__response__ = Array response
super schema, settings, :responses, @__response__.first.to_i
end

def __call__
super do
__check_status__
instance_exec(*@__response__, &__blocks__.last)
catch(PROCESSING_DONE) do
__blocks__.reverse_each do |block|
catch(SKIP_RESPONSE) do
throw(PROCESSING_DONE, instance_exec(*@__response__, &block))
end
end
# We're here if 1) no blocks or 2) all blocks skipped processing
raise ResponseError.new(@__schema__, @__settings__, @__response__)
end
end
end

def __check_status__
return if __blocks__.any?
raise ResponseError.new(@__schema__, @__settings__, @__response__)
def super!
throw SKIP_RESPONSE
end
end
end
24 changes: 22 additions & 2 deletions spec/unit/resolver/response_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
let(:logger) { Logger.new log }
let(:response) { [201, { "Content-Language" => "en" }, ["success"]] }

let(:root_response_handler) { proc { |*args| args } }
let(:root_schema) do
double :my_parent_schema,
definitions: { responses: { 201 => proc { |*args| args } } },
definitions: { responses: { 201 => root_response_handler } },
parent: nil
end

let(:response_handler) { proc { |_, _, body| body.first } }
let(:schema) do
double :my_schema,
definitions: {
responses: { 201 => proc { |_, _, body| body.first } }
responses: { 201 => response_handler }
},
parent: root_schema
end
Expand Down Expand Up @@ -53,6 +55,24 @@
end
end

context "when root definition reloaded but schema handler skips response" do
let(:response_handler) do
proc { |_, _, _| super! }
end

it "applies root schema to response" do
expect(subject).to eq response
end

context "when root definition skips response handling too" do
let(:root_response_handler) { proc { super! } }

it "raises Evil::Client::ResponseError" do
expect { subject }.to raise_error Evil::Client::ResponseError
end
end
end

context "when no definitions was given for the status" do
let(:response) { [202, { "Content-Language" => "en" }, ["success"]] }

Expand Down

0 comments on commit f6abe17

Please sign in to comment.