Skip to content

Commit

Permalink
Add plain body sending to Flexirest
Browse files Browse the repository at this point in the history
  • Loading branch information
andyjeffries committed Sep 5, 2019
1 parent 20e4269 commit 11e8aa6
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 19 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 1.8.0

Features:

- For the weird situations where the remote API expects some weird formatted input, you can now specify a `request_body_type` of plain and pass in to the call `body` (and optionally `content_type`) to pass it untouched to the API. The [docs](docs/body-types.md) have been updated.

## 1.7.9

Features:
Expand Down
10 changes: 10 additions & 0 deletions docs/body-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ class Person < Flexirest::Base
end
```

If your API expects some weird formatting on the requests, but you still want to use Flexirest for caching, response parsing, other models, etc you can pass `:plain` as the request body type either at the class level or method mapping level, and this will be passed through to the API. By default `plain` requests are sent with the `Content-Type: text/plain` header, but you can override this with `:content_type` when calling the mapped method.

```ruby
class Person < Flexirest::Base
put :save, '/person/:id/logs', request_body_type: :plain
end

Person.save(id: 1, body: '["Something here"]',
content_type: "application/json")
```

-----

Expand Down
23 changes: 23 additions & 0 deletions lib/flexirest/active_model_form_support.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Flexirest::ActiveModelFormSupport
extend ActiveSupport::Concern
include ActiveModel::AttributeAssignment
include ActiveModel::Validations
include ActiveModel::Conversion

included do
extend ActiveModel::Naming
extend ActiveModel::Translation
end

def persisted?
!dirty?
end

def new_record?
id.blank?
end

def errors
ActiveSupport::HashWithIndifferentAccess.new([]).merge(self[:errors] || {})
end
end
4 changes: 4 additions & 0 deletions lib/flexirest/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ def prepare_request_body(params = nil)
end
end
headers["Content-Type"] ||= "application/json; charset=utf-8"
elsif request_body_type == :plain && @post_params[:body].present?
@body = @post_params[:body]
headers["Content-Type"] ||= "text/plain"
headers["Content-Type"] = @post_params[:content_type] if @post_params[:content_type].present?
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/flexirest/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Flexirest
VERSION = "1.7.9"
VERSION = "1.8.0"
end
52 changes: 34 additions & 18 deletions spec/lib/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ class ExampleClient < Flexirest::Base
end
end

get :all, "/", :has_many => {:expenses => ExampleOtherClient}
get :flat, "/", :params_encoder => :flat
get :all, "/", has_many: {expenses: ExampleOtherClient}
get :flat, "/", params_encoder: :flat
get :array, "/johnny", array: [:likes, :dislikes]
get :babies, "/babies", :has_many => {:children => ExampleOtherClient}
get :single_association, "/single", :has_one => {:single => ExampleSingleClient}, :has_many => {:children => ExampleOtherClient}
get :babies, "/babies", has_many: {children: ExampleOtherClient}
get :single_association, "/single", has_one: {single: ExampleSingleClient}, has_many: {children: ExampleOtherClient}
get :headers, "/headers"
get :cancel_callback, "/cancel-callback"
put :headers_default, "/headers_default"
Expand All @@ -54,12 +54,12 @@ class ExampleClient < Flexirest::Base
get :requires, "/requires", requires:[:name, :age]
patch :only_changed_1, "/changed1", only_changed: true
patch :only_changed_2, "/changed2", only_changed: [:debug1, :debug2]
patch :only_changed_3, "/changed3", only_changed: { :debug1 => false, :debug2 => true }
patch :only_changed_3, "/changed3", only_changed: { debug1: false, debug2: true }
end

class ExampleLoadBalancedClient < Flexirest::Base
base_url ["http://api1.example.com", "http://api2.example.com"]
get :all, "/", :has_many => {:expenses => ExampleOtherClient}
get :all, "/", has_many: {expenses: ExampleOtherClient}
end

class AuthenticatedExampleClient < Flexirest::Base
Expand Down Expand Up @@ -135,7 +135,7 @@ class LazyLoadedExampleClient < ExampleClient
base_url "http://www.example.com"
lazy_load!
get :fake, "/fake", fake:"{\"result\":true, \"list\":[1,2,3,{\"test\":true}], \"child\":{\"grandchild\":{\"test\":true}}}"
get :lazy_test, "/does-not-matter", fake:"{\"people\":[\"http://www.example.com/some/url\"]}", :lazy => [:people]
get :lazy_test, "/does-not-matter", fake:"{\"people\":[\"http://www.example.com/some/url\"]}", lazy: [:people]
end

class VerboseExampleClient < ExampleClient
Expand Down Expand Up @@ -169,9 +169,9 @@ class IgnoredMultiLevelRootExampleClient < ExampleClient
{
"response": {
"data": {
"object": {
"object": {
"title": "Example Multi Level Feed"
}
}
}
}
}
Expand Down Expand Up @@ -340,12 +340,12 @@ class WhitelistedDateClient < Flexirest::Base

it "should pass through 'array type' get parameters" do
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/?include%5B%5D=your&include%5B%5D=friends", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.all :include => [:your,:friends]
ExampleClient.all include: [:your,:friends]
end

it "should pass through 'array type' get parameters using the same parameter name if a flat param_encoder is chosen" do
expect_any_instance_of(Flexirest::Connection).to receive(:get).with("/?include=your&include=friends", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.flat :include => [:your,:friends]
ExampleClient.flat include: [:your,:friends]
end

it "should encode the body in a form-encoded format by default" do
Expand All @@ -359,12 +359,28 @@ class WhitelistedDateClient < Flexirest::Base
ExampleClient.update id:1234, debug:true, test:'foo'
end

it "should encode the body in a JSON format if specified" do
it "should encode the body wrapped in a root element in a JSON format if specified" do
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"example":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.request_body_type :json
ExampleClient.wrapped id:1234, debug:true, test:'foo'
end

it "should pass the body untouched if plain format is specified on the class" do
header_expectation = {headers: {"Accept"=>"application/hal+json, application/json;q=0.5", "Content-Type"=>"text/plain"}, api_auth: {api_auth_access_id: "id123", api_auth_secret_key: "secret123", api_auth_options: {}}}
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", "debug:true|test:'foo'", header_expectation).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.request_body_type :plain
ExampleClient.update id:1234, body: "debug:true|test:'foo'"
end

it "should use the content type specified if plain format is specified on the class" do
header_expectation = {headers: {"Accept"=>"application/hal+json, application/json;q=0.5", "Content-Type"=>"application/flexirest"}, api_auth: {api_auth_access_id: "id123", api_auth_secret_key: "secret123", api_auth_options: {}}}
expect_any_instance_of(Flexirest::Connection).to receive(:put).
with("/put/1234", "debug:true|test:'foo'", header_expectation).
and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.request_body_type :plain
ExampleClient.update id:1234, body: "debug:true|test:'foo'", content_type: "application/flexirest"
end

it "should wrap elements if specified, in form-encoded format" do
expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(example%5Bdebug%5D=true&example%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
ExampleClient.wrapped id:1234, debug:true, test:'foo'
Expand Down Expand Up @@ -897,7 +913,7 @@ class WhitelistedDateClient < Flexirest::Base
end

it "should raise an exception if you try to pass in an unsupport method" do
method = {:method => :wiggle, url:"/"}
method = {method: :wiggle, url:"/"}
class RequestFakeObject < Flexirest::Base
base_url "http://www.example.com/"

Expand Down Expand Up @@ -944,17 +960,17 @@ def verbose ; false ; end

it "should retry if an after_request callback returns :retry" do
stub_request(:get, "http://www.example.com/do_me_twice").
to_return(:status => 200, :body => "", :headers => {})
to_return(status: 200, body: "", headers: {})
RetryingExampleClient.reset_retries
RetryingExampleClient.do_me_twice
expect(RetryingExampleClient.retries).to eq(2)
end

it "should allow a second call and then retry if an after_request callback returns :retry" do
stub_request(:get, "http://www.example.com/first_call").
to_return(:status => 200, :body => "", :headers => {})
to_return(status: 200, body: "", headers: {})
stub_request(:get, "http://www.example.com/second_call").
to_return(:status => 200, :body => "", :headers => {})
to_return(status: 200, body: "", headers: {})
RetryingExampleClient.reset_retries
RetryingExampleClient.first_call
expect(RetryingExampleClient.retries).to eq(2)
Expand Down Expand Up @@ -1023,7 +1039,7 @@ class OtherServerExampleClient < Flexirest::Base
end

it "should recognise a HAL response" do
method = {:method => :get, url:"/"}
method = {method: :get, url:"/"}
class RequestFakeObject
def base_url
"http://www.example.com/"
Expand Down Expand Up @@ -1137,7 +1153,7 @@ def _callback_request(*args) ; end
it "should ignore a specified root element" do
expect(IgnoredRootExampleClient.root.title).to eq("Example Feed")
end

it "should ignore a specified multi-level root element" do
expect(IgnoredMultiLevelRootExampleClient.multi_level_root.title).to eq("Example Multi Level Feed")
end
Expand Down

0 comments on commit 11e8aa6

Please sign in to comment.