flexirest / flexirest Goto Github PK
View Code? Open in Web Editor NEWFlexirest - The really flexible REST API client for Ruby
License: Other
Flexirest - The really flexible REST API client for Ruby
License: Other
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
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
I was evaluating this as an alternative to Her (https://github.com/remiprev/her/) - I can't find any mention of jsonapi (http://jsonapi.org) in the docs, is it supported?
I use the has_many
feature which is great but is it possible to chain has_many definitions in a class when the JSON response is deeply nested?
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
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?
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
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?
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.
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:indump' from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.22/lib/flexirest/caching.rb:73:in
write_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
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!" }
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.
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:inparse' from /home/dev0/.rvm/gems/ruby-2.3.0/gems/flexirest-1.3.24/lib/flexirest/attribute_parsing.rb:9:in
parse_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
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.
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?
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
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!
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.
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.
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.
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?
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!
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
I expected to be able to access the attr
id
.
>> Community.find(1).first
=> #<Community id: 1>
>> Community.find(1).first.id
=> 1
Instead, I get nil
returned.
>> Community.find(1).first
=> #<Community id: 1>
>> Community.find(1).first.id
=> nil
i want enable verbose!
for all class. but how set verbose default as true globally. i dont want to declare verbose! to each class.
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
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!
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.
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...
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?
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 :)
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
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 '/'.
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].
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?
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?
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)
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.
I don't think the {before,after}_request
s 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
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?
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 ?
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.
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
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.
I have to set manually on inherited class to make it working.
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)
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...)
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
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
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.
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)
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.
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.