Coder Social home page Coder Social logo

flexirest's Issues

Running Flexirest with warnings enabled

This isn't terribly important, but it would be nice to be able to keep warning counts down.

  Flexirest (0.7ms) RSpec::ExampleGroups::CoursemologyEvaluatorModelsBase::ModelKey::DummyModel#save
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/request.rb:245: warning: instance variable @forced_url not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/request_filtering.rb:24: warning: instance variable @before_filters not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:182: warning: instance variable @proxy not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/request.rb:245: warning: instance variable @forced_url not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/request_filtering.rb:24: warning: instance variable @before_filters not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:85: warning: instance variable @request_body_type not initialized
vendor/bundle/ruby/2.3.0/gems/flexirest-1.2.16/lib/flexirest/configuration.rb:182: warning: instance variable @proxy not initialized
  Flexirest (0.8ms) RSpec::ExampleGroups::CoursemologyEvaluatorModelsBase::ModelKey::DummyModel#save

ResultIterator method missing

When using the new has_many feature with deeply nested models I would see the following error:

NoMethodError:
        undefined method `[]=' for #<Flexirest::ResultIterator:0x007fa4bf231e08>

Adding the following monkey patch solved the issue. Do you see any issue with adding this to the class?

module Flexirest
  class ResultIterator

    def []=(key, value)
      @items[key] = value
    end

  end
end

API Auth - SHA256

Hopefully in the right place for this...

We leverage flexirest to communicate between two applications using api-auth. We would like to have flexirest sign the requests using a sha256 digest as described in the api-auth repository. The next release of api-auth enables different digests and then specifying this within the authorization header.

For example:

digest = OpenSSL::Digest.new('sha256')

and then being able to have APIAuth authenticate using that sha256:

head(:unauthorized) unless @current_account && ApiAuth.authentic?(request, @current_account.secret_key, :digest => 'SHA256')

and in the header:

APIAuth-HMAC-SHA256 'id':'secret_key'

Curious if there are settings or configurations where we can drive this behavior in the initializer

Undefined method 'expires' for #<String:0x0...>

I have been swapping out Active Rest Client for Flexirest on a branch. Thus far I have swapped out the initializer and the base model inherited class to be Flexirest::Base as well as swapped out all exception handlers.

But any model I call yields this error:

$ s = Series.all
NoMethodError: undefined method `expires' for #<String:0x007f83be516000>
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/flexirest-1.2.11/lib/flexirest/request.rb:158:in `block in call'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164:in `block in instrument'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/activesupport-4.2.4/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/activesupport-4.2.4/lib/active_support/notifications.rb:164:in `instrument'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/flexirest-1.2.11/lib/flexirest/request.rb:135:in `call'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/flexirest-1.2.11/lib/flexirest/mapping.rb:46:in `_call'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/flexirest-1.2.11/lib/flexirest/mapping.rb:28:in `block in _map_call'
    from (irb):15
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/railties-4.2.4/lib/rails/commands/console.rb:110:in `start'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/railties-4.2.4/lib/rails/commands/console.rb:9:in `start'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:68:in `console'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /Users/johnhenderson/.rvm/gems/ruby-2.2.3/gems/railties-4.2.4/lib/rails/commands.rb:17:in `<top (required)>'
    from bin/rails:8:in `require'
    from bin/rails:8:in `<main>'

from line 158 out of the request.rb from this block:

if cached
          if cached.expires && cached.expires > Time.now
            Flexirest::Logger.debug "  \033[1;4;32m#{Flexirest::NAME}\033[0m #{@instrumentation_name} - Absolutely cached copy found"
            return handle_cached_response(cached)
          elsif cached.etag.to_s != "" #present? isn't working for some reason
            Flexirest::Logger.debug "  \033[1;4;32m#{Flexirest::NAME}\033[0m #{@instrumentation_name} - Etag cached copy found with etag #{cached.etag}"
            etag = cached.etag
          end
        end

Is there something that I'm missing that needs to be swapped out and/or set in a config?

Caching

I feel like an idiot, but I can't for the life of me figure out how to get Flexirest to cache responses from the API. Can anyone help me out? I have Memcachier set up in Rails. Every time I hit the API, it looks like Flexirest is trying to read from the cache, but it doesn't actually write anything to the cache once it calls the API

Defining proxy class in parent class does not work

I have the following setup:

# service/base.rb
module Service
  class Unwrapper < Flexirest::ProxyBase
    get %r(.*) do
      response = passthrough
      translate(response) do |body|
        ...
      end
    end
  end

  class Base < Flexirest::Base
    proxy Service::Unwrapper
    ...  
  end 
end

---
# service/report.rb
module Service
  class Report < Service::Base
    ...
  end
end

However, the proxy does not work when I define it in the parent class. It initializes it correctly, but the regexp-method within the Unwrapper proxy does not fire. It works only if I put the proxy statement it in the Service-class, but this is not very DRY. I will be having lots of classes under the Base class.

I tried the following, but it didn't work either:

# service/base.rb (within the Base class)
...
def self.included(base)
  base.class_eval do
    proxy Service::Unwrapper
  end
end

Am I overlooking something here? Should I define the proxy class different?

Timeout settings not being respected

I am using flexirest to issue rest calls from inside the worker thread created by sneakers:run.

I added debugging puts statements to the connection.rb class (in the post method) and can verify that my connection timeout setting is 60 seconds, but when I execute the code I am seeing it timeout in less than 2.
Something about how flexirest is running when inside the sneakers thread is making the timeout settings be ignored, or at least that the best I can tell. I have verfiied that it's a Flexirest::Timeoutexecption that is being returned from the call.

I know this is a weird setup, and it's possible that the sneakers side is really the problem, but I have exhausted my debugging ability trying to track this down.

[Caching] TypeError: can't dump hash with default proc

hi,
i have an example rails api only app and able to access the resource with flexirest.
at this point when i add relation to the api like; has_many todo_list, the result request from flexirest throwing an error TypeError: can't dump hash with default proc
here is the verbose log from rails console

user = TodoUser.new
user.find(1)
Flexirest TodoUser:/users/1 - Trying to read from cache
Flexirest TodoUser#find - Etag cached copy found with etag W/"41e531b5dbb2eed26d6adb311236335e"
Flexirest TodoUser#find - Requesting http://dev0.todo.org/api/v1/users/1
Flexirest Verbose Log:
Request
GET /api/v1/users/1 HTTP/1.1
If-None-Match : W/"41e531b5dbb2eed26d6adb311236335e"
Accept : application/hal+json, application/json;q=0.5
Authorization : Token token=(redacted),email=[email protected]
Content-Type : application/json; charset=utf-8
Body:
{}
Response
<< Status : 200
<< date : Thu, 14 Jul 2016 03:28:39 GMT
<< server : Apache/2.2.22 (Debian)
<< cache-control : max-age=0, private, must-revalidate
<< etag : W/"7ad58789e399fd597f2164af5a614395"
<< x-frame-options : SAMEORIGIN
<< x-xss-protection : 1; mode=block
<< x-content-type-options : nosniff
<< x-runtime : 0.028518
<< x-request-id : 4e888626-7044-4563-84e8-ab203f8dd4b3
<< x-powered-by : Phusion Passenger 5.0.28
<< status : 200 OK
<< keep-alive : timeout=5, max=100
<< connection : Keep-Alive
<< transfer-encoding : chunked
<< content-type : application/json; charset=utf-8
<< Body:
{"id":1,"email":"[email protected]","name":"Administrator","username":"admin","activated":true,"activated_at":"2016-07-01T19:25:07.000Z","created_at":"2016-07-01T19:24:55.000Z","updated_at":"2016-07-14T03:28:22.000Z","todo_list":[{"id":1,"name":"testname1","todo_user_id":1,"created_at":"2016-07-06T19:01:07.000Z","updated_at":"2016-07-06T19:12:27.000Z"},{"id":2,"name":"testname2","todo_user_id":1,"created_at":"2016-07-06T19:13:27.000Z","updated_at":"2016-07-06T19:21:43.000Z"}]}
Flexirest TodoUser#find - Response received 605 bytes
Flexirest TodoUser:/users/1 - Writing to cache
Flexirest (48.5ms) TodoUser#find
TypeError: can't dump hash with default proc
from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.22/lib/flexirest/caching.rb:73:in dump' from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.22/lib/flexirest/caching.rb:73:inwrite_cached_response'
from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.22/lib/flexirest/request.rb:215:in `block (2 levels) in call'
--snipp

i do quick investigating flexirest/caching.rb line 73 and little google find myself here its about error of marshal dump that can't be done if it's an Object.new/Lambda i don't quite understand as i never use Marshal before.

now the quick fix for me is just rescue the error and implement suggest from the link like so
in a write_cached_response method i alter just before cache_store.write was execute

begin
    cache_store.write(key, Marshal.dump(cached_response), {}) if cached_response.etag.present? || cached_response.expires
rescue TypeError
    cached_response.result = {}.merge(result)
    cache_store.write(key, Marshal.dump(cached_response), {}) if cached_response.etag.present? || cached_response.expires
end

i was able to handle the error and it works but honestly is this ok?
thanks

Custom message for validations

At the moment there is no way to set a custom text for an error, unless you validate using a block. In AR validations you can do something like this:
validates :name, length: { minimum: 2, message: "Hey, name is too short!" }

Seven character numeric strings are being falsely interpreted as dates

When a value includes a string like "1266126", the regex on line 27 in Flexirest::Base is falsely interpreting it as a date, and parsing it.

Could the regex be more explicit in checking date values, using a regex like the following:

^((19|20)\d\d[- \/.](0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9]))|((0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9])[- \/.](19|20)\d\d)$

This requires that the string be in US or EU style, with delimiters.

[AttributeParsing] TypeError: no implicit conversion of DateTime into String

hi,
flexirest fail while trying to read respond from cache. the error occur in flexirest/attribute_parsing.rb
below is rails console verbose output

TodoUser.find(1)
Flexirest TodoUser:/users/1 - Trying to read from cache
Flexirest TodoUser#find - Requesting http://dev0.todo.org/api/v1/users/1
Flexirest Verbose Log:
Request
GET /api/v1/users/1 HTTP/1.1
Accept : application/hal+json, application/json;q=0.5
Authorization : Token token=[redacted],email=[email protected]
Content-Type : application/json; charset=utf-8
Body:
{}
Response
<< Status : 200
<< date : Fri, 15 Jul 2016 04:47:28 GMT
<< server : Apache/2.2.22 (Debian)
<< cache-control : max-age=0, private, must-revalidate
<< etag : W/"cfa2b7171212da8a9965e6d266df9fca"
<< x-frame-options : SAMEORIGIN
<< x-xss-protection : 1; mode=block
<< x-content-type-options : nosniff
<< x-runtime : 0.014644
<< x-request-id : 15ac1c09-8c24-4908-aac3-1768771e50ea
<< x-powered-by : Phusion Passenger 5.0.28
<< status : 200 OK
<< keep-alive : timeout=5, max=100
<< connection : Keep-Alive
<< transfer-encoding : chunked
<< content-type : application/json; charset=utf-8
<< Body:
{"id":1,"email":"[email protected]","name":"Administrator","username":"admin","activated":true,"activated_at":"2016-07-01T19:25:07.000Z","created_at":"2016-07-01T19:24:55.000Z","updated_at":"2016-07-15T04:41:57.000Z","todo_list":[{"id":1,"name":"testname1"},{"id":2,"name":"testname2"}]}
Flexirest TodoUser#find - Response received 423 bytes
Flexirest TodoUser:/users/1 - Writing to cache
Flexirest (42.9ms) TodoUser#find
=> #<TodoUser id: 1, email: "[email protected]", name: "Administrator", username: "admin", activated: true, activated_at: "2016-07-01 19:25:07", created_at: "2016-07-01 19:24:55", updated_at: "2016-07-15 04:41:57", todo_list: [#<TodoUser id: 1, name: "testname1">, #<TodoUser id: 2, name: "testname2"], ETag: W/"cfa2b7171212da8a9965e6d266df9fca", Status: 200>
TodoUser.find(1)
Flexirest TodoUser:/users/1 - Trying to read from cache
Flexirest TodoUser#find - Etag cached copy found with etag W/"cfa2b7171212da8a9965e6d266df9fca"
Flexirest TodoUser#find - Requesting http://dev0.todo.org/api/v1/users/1
Flexirest Verbose Log:
Request
GET /api/v1/users/1 HTTP/1.1
If-None-Match : W/"cfa2b7171212da8a9965e6d266df9fca"
Accept : application/hal+json, application/json;q=0.5
Authorization : Token token=[redacted],email=[email protected]
Content-Type : application/json; charset=utf-8
Body:
{}
Response
<< Status : 304
<< date : Fri, 15 Jul 2016 04:47:31 GMT
<< server : Apache/2.2.22 (Debian)
<< connection : Keep-Alive
<< keep-alive : timeout=5, max=100
<< etag : W/"cfa2b7171212da8a9965e6d266df9fca"
<< cache-control : max-age=0, private, must-revalidate
<< Body:
Flexirest TodoUser#find - Etag copy is the same as the server
Flexirest (28.1ms) TodoUser#find
TypeError: no implicit conversion of DateTime into String
from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.24/lib/flexirest/attribute_parsing.rb:9:in parse' from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.24/lib/flexirest/attribute_parsing.rb:9:inparse_attribute_value'
--snipp

i find a similar error here they fix it with Always convert date metadata to string to avoid parse errors

looking at the flexirest/attribute_parsing.rb
i add .to_s and it work fine

def parse_attribute_value(v)
   if v.to_s[(/\A(((19|20)\d\d[- \/.](0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9]))|((0[1-9]|1[012]|[1-9])[- \/.](0[1-9]|[12][0-9]|3[01]|[1-9])[- \/.](19|20)\d\d))\Z/)]
     Date.parse(v)
   elsif v.to_s[/\A([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?))\Z/]
     DateTime.parse(v.to_s)
   else
     v
   end
end

i remove tmp/cache and make the request twice again and it works with no error.
when i make 2nd request it gives the respond output like below

=> #<TodoUser id: 1, email: "[email protected]", name: "Administrator", username: "admin", activated: true, activated_at: "2016-07-01 19:25:07", created_at: "2016-07-01 19:24:55", updated_at: "2016-07-15 06:43:47", todo_list: [#<TodoUser id: 1, name: "testname1">, #<TodoUser id: 2, name: "testname2"] (unsaved: id, email, name, username, activated, activated_at, created_at, updated_at, todo_list)>

there is inspection in the output above unsaved because the result has @dirty_attributes?
is this ok? are this .to_s is a correct fix?
thanks

Caching an array leads to `undefined method ´ response_headers'`

The API which I am talking to, always returns an object starting with a 'data' key, with its value either an array of record hashes or an single hash containing a record.

With a proxy class, I try to set the response body so that the body is the 'data' value (so either an array of hashes or single hash).

I have the following setup:

# service/base.rb
module Service
  class Unwrapper < Flexirest::ProxyBase
    get %r(.*) do
      response = passthrough
      translate(response) do |body|
        body["data"]
      end
    end
  end

  class Base < Flexirest::Base
    proxy Service::Unwrapper
    ...  
  end 
end

This works fine. However, only when I don't turn on caching: Flexirest::Base.perform_caching = true. When I turn on caching, and I get an array back from the API:

{"data": [
    ...
]}

It will put the array in the cache, and the next time when it gets a cache hit, the following exception occurs:

NoMethodError: undefined method `response_headers' for #<Flexirest::CachedResponse:0x000000091671b0>
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/activesupport-3.2.22.2/lib/active_support/core_ext/object/try.rb:36:in `try'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/result_iterator.rb:10:in `initialize'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/caching.rb:107:in `new'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/caching.rb:107:in `result'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/request.rb:382:in `handle_cached_response'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/request.rb:401:in `handle_response'
	from /home/mike/.rbenv/versions/1.9.3-p448/lib/ruby/gems/1.9.1/gems/flexirest-1.3.27/lib/flexirest/request.rb:213:in `block (2 levels) in call'

I tested on both development and production environment. This seems only to fail with arrays, not single hashes.

Flexirest::ResponseParseException

I am calling a url that returns json. The format of the URL has /familiies.json as the end point. The json is valid, but I'm getting a Flexirest::ResponseParseException when it's called.

The response header has Content-Type = text/plain is that reason?

When verbose! is enabled, the json is shown in log, with a status of 200

Flexirest Verbose Log:
  Request
  >> GET /weblib/prod/catalog/families.json HTTP/1.1
  >> Accept : application/hal+json, application/json;q=0.5
  >> Content-Type : application/x-www-form-urlencoded
  >> Body:

  Response
  << Status : 200
  << date : Tue, 02 Feb 2016 21:52:56 GMT
  << server : Apache
  << last-modified : Tue, 02 Feb 2016 02:25:54 GMT
  << etag : "4d84d7-20f2-3886d080"
  << accept-ranges : bytes
  << content-length : 8434
  << connection : close
  << content-type : text/plain
  << Body:
{"families":{ <i've truncated the rest of the response>

Then after the json is shown i get this

  Flexirest (142.0ms) ProductFamily#all
Completed 500 Internal Server Error in 149ms (Flexirest: 142.0ms for 1 calls | ActiveRecord: 0.0ms)

Flexirest::ResponseParseException (Flexirest::ResponseParseException):

The model "product_family.rb" has the base_url defined, and a get :all, "/families.json"

When i put this url in postman or the web browser, it does display the json.

What is Flexirest expecting that this if failing?

Render user entered data in rescue block if update fails

Hi,

I have rails 5.0.1 app (App 1) working which uses another Rails API for database operations.
App 1 is not using active record.
App 1 is using flexirest for Api calls.

When create or update method is called, all the data is sent to rails api in json format.
i want when api throws any error, it should be catch in rescue block and also the data which user entered before submit click should be render after rescue using render :edit (for update) or render :new (for create)

here is my code

def update
    respond_to do |format|
      begin
        if @booking.update({id: @booking.booking.id, booking: booking_params})  
          format.html { redirect_to excel_front_innstats_path, notice: display_notice(t("label.detailed_reservation.reservation")) }
        else
          format.html { render :edit }
        end
      rescue => e
        #here assign the booking object with user entered data, 
        #so that the form will not loose the data, if exception occurs
        flash_error_message(:error, e.result)
        format.html { render :edit }
      end  
    end
  end

ignore_root option not working?

First off, thank you @andyjeffries for implementing the ignore_root option quickly... I just updated my installed version of the gem to the latest version which includes that option.

I still keep getting this error: undefined method `name' for :coupons:Symbol
The only way for me to fix this is to do

@coupon = Coupon.all
@coupon = @coupon.coupons

Am I calling the option incorrectly in my model file?

class Coupon < Flexirest::Base
    extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  request_body_type :json

    get :all, "/coupons", ignore_root: "coupons"
    get :find, "/coupons/:id", ignore_root: "coupon"
    put :update, "/coupons/:id"
    post :save, "/coupons"
    delete :destroy, "/coupons/:id"

    def persisted?
    id.present?
  end
end

Any help is appreciated!

Thanks!

Attribute parsing of dates isn't anchored and can't handle nil. Fails on certain dates and nil values.

If a value contains a date that isn't completely parsable by Date it still triggers the regex and then fails. It also fails if the value is nil. Looking at where it's called in Flexirest::Request#new_object that regex is reparsed and called on every non-Hash/Array object which has to be non-optimal. Date parsing is also sensitive to timezone and other localizations that would affect the outcome.

Attribute parsing should be optional on a route so the caller can handle special cases.

Plain Request with Basic-Auth

Hello,

I have a class wich has its own base url, username and password for Basic-Auth authentication, and I try to get the content as string at the following URL :

self._plain_request( self.base_url + a_dynamic_path )

But the Basic-Auth is something like skipped in the request process. I suspect something near lines 378-379 to use a local 'base_url' variable which is not yet defined.

base_url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if username && !base_url[%r{//[^/]*:[^/]*@}]
connection = Flexirest::ConnectionManager.get_connection(base_url)

Using either @base_url or self.base_url is working but as I don't know what could be influenced after that modification, I prefer to let you know about it.

By the way, I didn't find any public URL with basic-auth and rendering in text/plain to show you, sorry for that.

Thanks for your answer.

Possible to do a find on collection?

Hi There,

Just wondering if this would be possible.
I am doing a call for a user, which also returns multiple shops.

Currently it isn't possible to do a: current_user.shops.find(1).
In my case it returns an enumerator with the shops.

Is there a way to query by id without doing: Shop.find(2) ?
As I don't want another call to the api.

`prepare_url` deletes much-needed GET/POST params

Consider this line and the following URL structure: /conacts/:id.

An API I am integrating with needs ID in the URL and the post body as it matches the two for "verification". As the aforementioned line deletes this from get_params and post_params, my only reasonable option is to pull it from the params and re-include it with a proxy.

Shouldn't we reconsider the deletion of such attributes?

`attr` returning `nil`

Thank you for this wonderful gem! I was hoping you could help me figure out this little problem I'm having. I'm probably just not understanding something or doing it wrong!

Problem

Using attr seems to block getting actual value.

class Community < Flexirest::Base
  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr :id

  get :find, '/communities', fake: ->(req) { req.prepare_params; [{id: req.get_params[:id]}] }
end

(My) Expected Result

I expected to be able to access the attr id.

>> Community.find(1).first
=> #<Community id: 1>
>> Community.find(1).first.id
=> 1

Actual Result

Instead, I get nil returned.

>> Community.find(1).first
=> #<Community id: 1>
>> Community.find(1).first.id
=> nil

how to set verbose mode globally

i want enable verbose! for all class. but how set verbose default as true globally. i dont want to declare verbose! to each class.

How to use pagination?

My code:

[1] pry(main)> Post.all.paginate(page: 1, per_page: 5)
  Flexirest Post:/posts?with_categories=true&with_tags=true - Trying to read from cache
  Flexirest Post#all - Etag cached copy found with etag W/"48c26506e97f78a13d739549acf973c1"
  Flexirest Post#all - Requesting http://api.local/v1/posts?with_categories=true&with_tags=true
  Flexirest Post#all - Etag copy is the same as the server
  Flexirest Post:/posts?with_categories=true&with_tags=true - Writing to cache
  Flexirest (3195.6ms) Post#all
=> nil

My model:

class Post < Base
  get :all, "/posts"
  get :find, "/posts/:id"

  before_request do |name, request|
    if name == :all
      request.get_params[:with_categories] = true
      request.get_params[:with_tags] = true
    end
  end
end

JSON Root

Does flexirest support parsing a root object in a JSON response like so?

{ coupon : { name: "test", discount: 20 } }

Right now in my code, I have to do
@coupon = Coupon.find(params[:id]) @coupon = @coupon.coupon

I was wondering if there is a simpler way to handle this.

Thanks!

Problem in proxies

Hi!

I have a problem using the proxy feature. I want to map a response to a array of arrays but when I try that i receive this error: no implicit conversion of Symbol into Integer.

I'm using the last version of the gem: 1.3.3.3

I have a code similar to this:

class ArticleProxy < Flexirest::ProxyBase
  get "/tags" do
    response = passthrough
    translate(response) do |body|
     body.map! do |article|
        [article['author'], article['name']]
      end
     body
    end
  end
end

The response is something like:

[ 
     { "id": 1, "author": 'Shakespeare', "name": "Romeu & Julieta" },
     { "id": 2, "author": "Dumas", "name": "3 Mosqueteers" }
]

I think the problem is in the method generate_new_object

More specifically:

..
 if body.is_a? Array
        result = Flexirest::ResultIterator.new(@response)
        body.each do |json_object|
          result << new_object(json_object, @overridden_name)
        end
..

Can you provide some help? Is this some bug or is not suposed to do that?

Thanks in advance.

Question - async nature of calls and processing of results

Sorry I couldn't think of another way to title this issue/question.

We leverage Flexirest to handle the integration between two apps. We do some of these calls to the other app via background jobs/sidekiq. Regardless there are times we will call the Flexirest model in one app and then use the values on a native/active record model.

For example, we call the flexirest object to get a single object from the api. We then instantiate a new native/active record object and populate one of those model attributes with the ID of the flexirest object. When we do this, we get

PG::NotNullViolation: ERROR: null value in column "budget_request_id" violates not-null constraint

due to us having validations on the db level ensuring that value is never null.

When you look at the object in the DB you see that the budget_request_id actually did get populated. My assumption with that is that Sidekiq retried the job and then Flexirest used the cache to grab the object.

Regardless my question is how am I supposed to be doing these types of things? My assumption the Flexirest call is async and thus when i am moving through my logic the values of the flexirest object haven't yet returned or been populated. Thus the reason for the null. Yet what is the best practice on how to do this where we know Flexirest has returned with the values so that we can use them.

Hopefully that makes sense...

Faraday Flat Params

I can't fpr the life of me figure out how to set Faraday::FlatParamsEncoder in the Faraday config block or on a per session basis. I've tried:

Flexirest::Base.faraday_config do |faraday|
    faraday.adapter(:net_http)
    faraday.options.timeout       = 10
    faraday.headers['User-Agent'] = "Flexirest/#{Flexirest::VERSION}"
    faraday.options.params_encoder = Faraday::FlatParamsEncoder
end

and

Flexirest::Base.faraday_config do |faraday|
  faraday.adapter(:net_http)
  faraday.options.timeout       = 10
  faraday.headers['User-Agent'] = "Flexirest/#{Flexirest::VERSION}"
  faraday.params_encoder = Faraday::FlatParamsEncoder
end

but my get params in a hash still have the brackets in the request url, which is invalid with the API I'm using. Any help?

Suggestion on plain requests

Hi mate

I have a question/suggestion.

So, as you know, to make a plain request I have to do something like:

.. 
Person._plain_request('http://api.example.com/v1/people', :post, {id:1234,name:"John"})

Why I cant do it like this?

.. 
Person.create(id:1234,name:"John", plain: true)

Also do you think to add multipart sometime?

Thanks :)

Filename too long on caching response

Hi,

In some cases, the request URI gets big. When it receives the response from the service, and it wants to cache this, it sometimes yields the following exception:

( I modified it a bit in order to hide the actual path, but you'll get the point )
Errno::ENAMETOOLONG: File name too long - /very/long/path/to/rails/project/tmp/cache/module_name%3A%3Aflexi_rest_class_name%3A%2F_method%3Ffilter%255Bsequence_number%255D%3D1012%26filter%255Byear%255D%3D2014%26include%3Djournals20161119-13300-p21hbf.lock

URL double encoding

I have a URL with a name that has a '/' (forward slash) in the name. So i escape it to %2F before making the call. Flexirest errors with a 404. I print out the exception it appears to be double encoded the %2F to %252. It appears that Flexirest is encoding the URL when the value is %2F, but doesn't do it with a '/'.

Duplicated hash keys and values

I have the Person resource which inherits from Flexirest::Base.

I invoke the #create method on the class instance as per the README:

@person = Person.create(
  first_name: “John”, 
  last_name: “Smith"
)

At the (Rails) server when I inspect the params, I get the following:

{“first_name”=>”John”, “last_name”=>”Smith”, “controller”=>”persons”, “action”=>”create”, 
“person”=>{“first_name”=>”John”, “last_name”=>”Smith”}}

Can you see the duplicated keys and values?

I’m wondering how I can avoid this?

I find that the strong parameters then causes first_name and last_name keys to be rejected (warning in log output) because I have:

params.require(:person).permit(:first_name, :last_name)

Any clues how I can have just the plan hash, or even just the individual key pairs (one or the other)?

If I use:

params.permit(:first_name, :last_name)

Then I get a warning about plan being rejected.

I am running Rails 5.0.0.beta2 and Ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin15].

Accessing the method in the default parameters

I have a fairly un-RESTful API I'd like to use. The API only supports POST requests of a complex query object that returns a JSON report object. For example:

A POST to /reports/portfolio/runFundsReport' of this object:
{ queryDefinition:'', filterDefinition: ', asOf:'datestring' }

Is the equivalent of an "get :all, '/funds'" mapping.

I've successfully implemented the :all method like this:

post :all, "/reports/portfolio/runFundsReport", :defaults => {queryDefinition:query,
                                                  restrictionExpression:'${(!like(report.field3, "Coinvestment"))}',
                                                asOf:DateTime.now.strftime('%Y-%m-%d')}

Now I need to implement the :find method by putting the ID in the restrictionExpression. How do you reference the parameter passed in the argument to Model.find(123) to the defaults? Or can you?

Thank you and question

First, thank you Andy for taking over and continuing development of FlexiRest (formally ActiveRestClient). As restful API's proliferate, having tools for consuming them based on conventions versus configurations become ever more important.

This is not an issue, but a question on best practices.

I need to add values to the body of all my requests. A Configuration module contains methods for setting and getting the userid and source values. Currently, I am doing the following.

module MyRestClient
  class Base < FlexiRest::Base
    include Configuration
    def initialize(args = {})
      super
      self.userid = self.class.userid
      self.source = self.class.source
    end

  end
end

module MyRestClient
  class Product < Base
    post :create, "/products"
  end
end

Is this the preferred method, or would you recommend another?

Not works with devise

If I include flexirest with user model which devise gem in it , it throws the following error

``class:User': undefined method devise' for User:Class (NoMethodError)

Problem updating a model

When updating a model. It seems like it doesn't assign the given attributes on time:
Given I have a hash like this:
{"user"=>{"id"=>"11", "first_name"=>"jaa", "last_name"=>"te Wies", "email"=>"[email protected]", "company_name"=>""}

And update it as follows:
@current_user.update(user_params)

It doesn't assign the given atttributes, but uses the old.
When I do the following, it works:
@current_user.update(user_params) @current_user.update(user_params)

So it seems, that the patch on the model already fires when it still has to assign the attributes.

Doing:
User.update(user_params)
Works as expected though.

{before,after}_request not triggered for faked response?

I don't think the {before,after}_requests are triggered for faked responses. Is this correct? I expected that they would be triggered..

Here's my isolated test case.

require 'flexirest'

class Foo < Flexirest::Base
  before_request do |name, req|
    puts "before request #{name}"
  end

  after_request do |name, res|
    puts "after request #{name}"
  end

  get :all, '/foo/:bar', fake: -> (req) {
    [{id: 1, yadda: 'yadda'}]
  }
end

Foo.all(bar: 1).each do |foo|
  p foo
end

Actual

#<Foo id: 1, yadda: "yadda">

Expected

before request :all
#<Foo id: 1, yadda: "yadda">
after request :all

Perform caching false does not work as expected

Hi,

When I define perform_caching false in a Flexirest::Base class, it is still caching all results when the responding service includes an ETag. I don't know for other Rails versions, but if the server is a Rails 5 API application, responses will always include an ETag.

I am using Flexirest 1.3.27.

I am printing the response in a proxy class:

#<Faraday::Response:0x00000008519fc0 @on_complete_callbacks=[], @env=#<Faraday::Env @method=:get @body="" @url=#<URI::HTTP:0x0000000850f4d0 URL:###> @request=#<Faraday::RequestOptions timeout=60> @request_headers={"User-Agent"=>"Flexirest/1.3.27", "If-None-Match"=>"3cef065214a766fedf6c09275645a193", "Accept"=>"application/json", "X-Api-Key"=>"0KadWOPf8x3Mb7zSLfZE1Qtt"} @ssl=#<Faraday::SSLOptions (empty)> @response=#<Faraday::Response:0x00000008519fc0 ...> @response_headers={"x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "x-content-type-options"=>"nosniff", "etag"=>"3cef065214a766fedf6c09275645a193", "cache-control"=>"max-age=0, private, must-revalidate", "x-request-id"=>"9e20d434-5719-4ce8-9208-ce1d814ddf99", "x-runtime"=>"0.784712", "connection"=>"close"} @status=304 @reason_phrase="Not Modified">>

I even tried on the server side to send back 200 OKs instead of 304 Not Modified (while still sending back the same ETag) to see if this affects something, but it didn't matter at all. The response is still as above (304). Even though I explicitly send back a 200 OK:

Completed 200 OK in 738ms (Views: 6.5ms | ActiveRecord: 0.6ms)

There seem to be strange things going on here. It seems to me that the client is basing it's response code on if the sent ETag is the same as the received ETag (making it 304), and not on the actual response code (200). Also, it seems to be ignoring the perform_cache false.

Let me know if you need a more elaborate explanation or help.

EDIT: The workaround I have for this right now, is defining Flexirest::Base.perform_caching = false in an initializer (or production.rb).

EDIT2: Could I have this issue because I am running my client in development environment?

Use CanCan with Flexirest

Hi,

I am using Flexirest with CanCan(Can) in my application and every thing works fine until today, I was checking the permission likes this:

can? :update, User

And that works fine, but know I want to be more specific, like you can only edit your own user so I added to ability.rb:

can :update, User, id: user.id 

But When I try to do:

can? :update @user

Rails returns:

TypeError - no implicit conversion of nil into Integer:
  cancancan (1.13.1) lib/cancan/ability.rb:379:in `possible_relevant_rules'
  cancancan (1.13.1) lib/cancan/ability.rb:367:in `relevant_rules'
  cancancan (1.13.1) lib/cancan/ability.rb:386:in `relevant_rules_for_match'
  cancancan (1.13.1) lib/cancan/ability.rb:67:in `block in can?'
  cancancan (1.13.1) lib/cancan/ability.rb:66:in `can?'
  cancancan (1.13.1) lib/cancan/controller_additions.rb:380:in `can?'
  actionpack (4.2.5.1) lib/abstract_controller/helpers.rb:67:in `can?'

When I use a ActiveRecord Object, I don´t have that problem.
Can you give me some hints ?

Dirty tracking with selective attributes for PATCH?

How about the optional addition of Mongoid style dirty tracking for model attributes, so that future updates (PATCHes) to an endpoint might only contain the attributes that have been changed, rather than the current full object.

Given the current loose implementation style of this gem, this feature might be best implemented as an optional setting on a per-action basis, much like how :ignore_root currently works.

Flexirest Thread Safety

Hi there,

First of all, thanks for the amazing work with Flexirest.
We've been using it for the past several months, but now that we're moving to Puma webserver, thread safety became a concern and after some digging we realised that it is not safe because it depends a lot on static variables, is there a plan to address this topic?
The relevant use case here would be to have a thread safe base_url, because we have logic that chooses it depending on the situation, and right now it happens that requests get some times called to the wrong base_url, because of that.

Thanks

Bug in Flexirest::Base#to_hash

Hi, great gem.
Getting an error in Base.to_hash due to the following line in the code. Namely, if value is an array, it assumes the members of the array have a to_hash method. But the array members could be primitives?
Cheers.

Plain request, with URL formatting

Is there any way to support plain requests while doing URL substitutions? I'd like to do something like this:

plain_request('courses/assessment/programming_evaluations/:id/package', id: id)

(from https://github.com/Coursemology/evaluator-slave/blob/master/lib/coursemology/evaluator/models/programming_evaluation.rb)

and URL substitution will replace id with the variable. Plain requests currently do not support that (all URLs are used verbatim), is there any reason for that?

I'm not directly returning the contents of that endpoint within my response for the rest of the record because that's a blob. (not supporting streamy response parsing is a separate issue...)

Error Exception handler

is there a away to rescue from exception in flexirest class?
eg:

class Bank < Flexirest::Base
   get  :find, "/banks/:id" do
      begin
        #passthrough
      rescue Flexirest::HTTPClientException, Flexirest::HTTPServerException => e
        Rails.logger.error("API returned #{e.status} : #{e.result.message}")
        render "{\"error\":1234}"
      end
   end
end

# no luck

Add id to response object

Hi,

When I call the create service, the service respond with the ID of the new object.

Flexirest, responds the object without the ID, how can i pass the ID?

Thanks

Adds singularized record name to parameters

I have the following setup on the client side within a Flexirest class:

class ReportService < Flexirest::Base
    request_body_type :json

    get :reports, '/reports',
        :defaults => {
          :filter => {
            :year => 2016
            }
          }
end

When I run this, on the server side, the following parameters are entered:
Parameters: {"filter"=>{"year"=>"2016"}, "report"=>{}}

What causes this report key in the parameters? This report key does not appear in the incoming parameters when I do an equivalent curl request:
curl -X GET 'https://.../reports?filter[year]=2016'
Parameters: {"filter"=>{"year"=>"2016"}

Thanks for your help.

Edit:
I found out that the problem goes away when I remove request_body_type :json from my Flexirest class.

Small helper for people who need to filter

As I need to filter results sometime, I made the following function.
just leaving it here if people are looking for it:

class Flexirest::ResultIterator
  def where(hash={})
    self.items.select do |object|
      select = true
        hash.each do |k, v| 
          select = false if object[k] != v
        end
        select
      end
   end
end

You can use it as follow:
People.all.where(admin: true)

Allow monkey patching NAME constant

Would you accept a pull request where I refactor the Flexirest::NAME constant to be a variable?

This would allow customisation of the name displayed in the console / logs.

Question: HAL + Associations

Hi!
I've a question about using associations with HAL.

I have two models for a photo and an attached image:

class HalImage < Flexirest::Base
   base_url "http://localhost:8080"

  get :find, "/test/hal/images/:id"

  def who_am_i
    "I'm an image"
  end
end

class HalPhoto < Flexirest::Base
  base_url "http://localhost:8080"

  # has_many :image, HalImage
  # has_one :image, HalImage

  get :find, "/test/hal/photos/:id" #,:has_one => {:image => HalImage}, :lazy => [:image]

  def who_am_i
    "I'm a photo"
  end
end

and a controller calling the model

class HalPhotosController < ApplicationController

  def index
    @photo = HalPhoto.find(1)
    @image = @photo.image
    puts "image-id: " + @image.id.to_s
    puts @image.inspect
    puts @image.class
    puts @image.who_am_i
  end

end

With the above setup I get the follwing console output: Data is lazy loaded, but @image seems to be an HalPhoto when calling the who_am_i method

image-id: 1
#<Flexirest::LazyAssociationLoader:0x0055698dda5718 @name="image", @request=#<Flexirest::Request:0x00[... shortened]
Flexirest::LazyAssociationLoader
I'm a photo

When I change the model and enable a has_one relation, the output changed:

image-id: 
#<HalImage self: nil, id: nil, filename: nil, content_type: nil, width: nil, height: nil (unsaved: self, id, filename, content_type, width, height)>
HalImage
I'm an image

The type is now, as expected, HalImage. But the values are not lazy loaded.

Server response to complete question:

{
  _links: {
    self: {
      href: "http://localhost:8080/test/hal/photos/1"
    },
    image: {
      href: "http://localhost:8080/test/hal/images/1"
    }
  },
  id: 1,
  caption: "a beautiful image"
}

Anyone, any further ideas to get it run?

Thanks a lot - Timo

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.