flexirest 1.6.5 → 1.6.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +92 -1243
- data/docs/associations.md +181 -0
- data/docs/authentication.md +76 -0
- data/docs/automatic-conversion-of-fields-to-datedatetime.md +34 -0
- data/docs/basic-usage.md +103 -0
- data/docs/body-types.md +33 -0
- data/docs/caching.md +26 -0
- data/docs/combined-example.md +72 -0
- data/docs/debugging.md +32 -0
- data/docs/default-parameters.md +37 -0
- data/docs/faking-calls.md +22 -0
- data/docs/faraday-configuration.md +28 -0
- data/docs/filtering-result-lists.md +16 -0
- data/docs/httpparse-error-handling.md +17 -0
- data/{CONTRIBUTING.md → docs/internals.md} +4 -6
- data/docs/json-api.md +42 -0
- data/docs/lazy-loading.md +31 -0
- data/{Migrating-from-ActiveRestClient.md → docs/migrating-from-activerestclient.md} +2 -2
- data/docs/parallel-requests.md +28 -0
- data/docs/per-request-parameter-encoding.md +32 -0
- data/docs/per-request-timeouts.md +13 -0
- data/docs/plain-requests.md +30 -0
- data/docs/proxying-apis.md +86 -0
- data/docs/raw-requests.md +38 -0
- data/docs/required-parameters.md +17 -0
- data/docs/root-elements.md +34 -0
- data/{Ruby-on-Rails-Integration.md → docs/ruby-on-rails-integration.md} +16 -12
- data/docs/{Flexirest Internals.graffle → source/Flexirest Internals.graffle} +0 -0
- data/docs/{Flexirest Logo.sketch → source/Flexirest Logo.sketch} +0 -0
- data/docs/translating-apis.md +31 -0
- data/docs/updating-only-changed-dirty-attributes.md +37 -0
- data/docs/using-callbacks.md +114 -0
- data/docs/validation.md +89 -0
- data/docs/xml-responses.md +58 -0
- data/lib/flexirest/configuration.rb +36 -20
- data/lib/flexirest/request.rb +12 -4
- data/lib/flexirest/version.rb +1 -1
- data/spec/lib/request_spec.rb +28 -0
- metadata +35 -7
@@ -0,0 +1,181 @@
|
|
1
|
+
# *Flexirest:* Associations
|
2
|
+
|
3
|
+
There are two types of association. One assumes when you call a method you actually want it to call the method on a separate class (as that class has other methods that are useful). The other is lazy loading related classes from a separate URL.
|
4
|
+
|
5
|
+
## Type 1 - Loading Other Classes
|
6
|
+
|
7
|
+
If the call would return a single instance or a list of instances that should be considered another object, you can also specify this when mapping the method using the `:has_one` or `:has_many` options respectively. It doesn't call anything on that object except for instantiate it, but it does let you have objects of a different class to the one you initially called.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Expense < Flexirest::Base
|
11
|
+
def inc_vat
|
12
|
+
ex_vat * 1.20
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Address < Flexirest::Base
|
17
|
+
def full_string
|
18
|
+
"#{self.street}, #{self.city}, #{self.region}, #{self.country}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Person < Flexirest::Base
|
23
|
+
get :find, "/people/:id", :has_many => {:expenses => Expense},
|
24
|
+
:has_one => {:address => Address}
|
25
|
+
end
|
26
|
+
|
27
|
+
@person = Person.find(1)
|
28
|
+
puts @person.expenses.reduce {|e| e.inc_vat}
|
29
|
+
puts @person.address.full_string
|
30
|
+
```
|
31
|
+
|
32
|
+
You can also use `has_one`/`has_many` on the class level to allow chaining of classes. You can specify the class name or allow the system to automatically convert it to the singular class. For example:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class Expense < Flexirest::Base
|
36
|
+
def inc_vat
|
37
|
+
ex_vat * 1.20
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Address < Flexirest::Base
|
42
|
+
def full_string
|
43
|
+
"#{self.street}, #{self.city}, #{self.region}, #{self.country}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Person < Flexirest::Base
|
48
|
+
has_one :addresses
|
49
|
+
has_many :expenses, Expense
|
50
|
+
get :find, "/people/:id"
|
51
|
+
end
|
52
|
+
|
53
|
+
class Company < Flexirest::Base
|
54
|
+
has_many :people
|
55
|
+
get :find, "/companies/:id"
|
56
|
+
end
|
57
|
+
```
|
58
|
+
|
59
|
+
Sometimes we want attributes to just return a simple Ruby Array. To achieve this we can add an `:array` option to the method. This is especially useful when the attribute contains an array of scalar values. If you don't specify the `:array` option Flexirest will return a `Flexirest::ResultIterator`. To illustrate the difference consider the following example:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
class Book < Flexirest::Base
|
63
|
+
# :authors attribute ["Robert T. Kiyosaki", "Sharon L. Lechter C.P.A"]
|
64
|
+
# :genres attribute ["self-help", "finance", "education"]
|
65
|
+
get :find, "/books/:name", array: [:authors]
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
In the example above, the following results can be observed:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
@book = Book.find("rich-dad-poor-dad")
|
73
|
+
puts @book.authors
|
74
|
+
#=> ["Robert T. Kiyosaki", "Sharon L. Lechter C.P.A"]
|
75
|
+
puts @book.authors.class
|
76
|
+
#=> Array
|
77
|
+
puts @book.genres
|
78
|
+
#=> #<Flexirest::ResultIterator:0x007ff420fe7a88 @_status=nil, @_headers=nil, @items=["self-help", "finance", "education"]>
|
79
|
+
puts @books.genres.class
|
80
|
+
#=> Flexirest::ResultIterator
|
81
|
+
puts @books.genres.items
|
82
|
+
#=> ["self-help", "finance", "education"]
|
83
|
+
```
|
84
|
+
|
85
|
+
When the `:array` option includes an attribute, it is assumed the values were returned with the request, and they will not be lazily loaded. It is also assumed the attribute values do not map to a Flexirest resource.
|
86
|
+
|
87
|
+
## Type 2 - Lazy Loading From Other URLs
|
88
|
+
|
89
|
+
When mapping the method, passing a list of attributes will cause any requests for those attributes to mapped to the URLs given in their responses. The response for the attribute may be one of the following:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
"attribute" : "URL"
|
93
|
+
"attribute" : ["URL", "URL"]
|
94
|
+
"attribute" : { "url" : "URL"}
|
95
|
+
"attribute" : { "href" : "URL"}
|
96
|
+
"attribute" : { "something" : "URL"}
|
97
|
+
```
|
98
|
+
|
99
|
+
The difference between the last 3 examples is that a key of `url` or `href` signifies it's a single object that is lazy loaded from the value specified. Any other keys assume that it's a nested set of URLs (like in the array situation, but accessible via the keys - e.g. object.attribute.something in the above example).
|
100
|
+
|
101
|
+
It is required that the URL is a complete URL including a protocol starting with "http". To configure this use code like:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class Person < Flexirest::Base
|
105
|
+
get :find, "/people/:id", :lazy => [:orders, :refunds]
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
And use it like this:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
# Makes a call to /people/1
|
113
|
+
@person = Person.find(1)
|
114
|
+
|
115
|
+
# Makes a call to the first URL found in the "books":[...] array in the article response
|
116
|
+
# only makes the HTTP request when first used though
|
117
|
+
@person.books.first.name
|
118
|
+
```
|
119
|
+
|
120
|
+
## Type 3 - HAL Auto-loaded Resources
|
121
|
+
|
122
|
+
You don't need to define lazy attributes if they are defined using [HAL](http://stateless.co/hal_specification.html) (with an optional embedded representation). If your resource has an `_links` item (and optionally an `_embedded` item) then it will automatically treat the linked resources (with the `_embedded` cache) as if they were defined using `:lazy` as per type 2 above.
|
123
|
+
|
124
|
+
If you need to, you can access properties of the HAL association. By default just using the HAL association gets the embedded resource (or requests the remote resource if not available in the `_embedded` list).
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
@person = Person.find(1)
|
128
|
+
@person.students[0]._hal_attributes("title")
|
129
|
+
```
|
130
|
+
|
131
|
+
## Type 4 - Nested Resources
|
132
|
+
|
133
|
+
It's common to have resources that are logically children of other resources. For example, suppose that your API includes these endpoints:
|
134
|
+
|
135
|
+
| HTTP Verb | Path | |
|
136
|
+
|-----------|-----------------------------|------------------------------------------|
|
137
|
+
| POST | /magazines/:magazine_id/ads | create a new ad belonging to a magazine |
|
138
|
+
| GET | /magazines/:magazine_id/ads | display a list of all ads for a magazine |
|
139
|
+
|
140
|
+
In these cases, your child class will contain the following:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
class Ad < Flexirest::Base
|
144
|
+
post :create, "/magazines/:magazine_id/ads"
|
145
|
+
get :all, "/magazines/:magazine_id/ads"
|
146
|
+
end
|
147
|
+
```
|
148
|
+
|
149
|
+
You can then access Ads by specifying their magazine IDs:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
Ad.all(magazine_id: 1)
|
153
|
+
Ad.create(magazine_id: 1, title: "My Add Title")
|
154
|
+
```
|
155
|
+
|
156
|
+
## Type 5 - JSON API Auto-loaded Resources
|
157
|
+
|
158
|
+
If attributes are defined using [JSON API](http://jsonapi.org), you don't need to define lazy attributes. If your resource has a `links` object with a `related` item, it will automatically treat the linked resources as if they were defined using `:lazy`.
|
159
|
+
|
160
|
+
You need to activate JSON API by specifying the `json_api` proxy:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
class Article < Flexirest::Base
|
164
|
+
proxy :json_api
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
If you want to embed linked resources directly in the response (i.e. request a JSON API compound document), use the `includes` class method. The linked resource is accessed in the same was as if it was lazily loaded, but without the extra request:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# Makes a call to /articles with parameters: include=images
|
172
|
+
Article.includes(:images).all
|
173
|
+
|
174
|
+
# For nested resources, the include parameter becomes: include=images.tags,images.photographer
|
175
|
+
Article.includes(:images => [:tags, :photographer]).all
|
176
|
+
```
|
177
|
+
|
178
|
+
|
179
|
+
-----
|
180
|
+
|
181
|
+
[< Faraday configuration](faraday-configuration.md) | [Combined example >](combined-example.md)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# *Flexirest:* Authentication
|
2
|
+
|
3
|
+
## Basic authentication
|
4
|
+
|
5
|
+
You can authenticate with Basic authentication by putting the username and password in to the `base_url` or by setting them within the specific model:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
class Person < Flexirest::Base
|
9
|
+
username 'api'
|
10
|
+
password 'eb693ec-8252c-d6301-02fd0-d0fb7-c3485'
|
11
|
+
|
12
|
+
# ...
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
You can also pass in a Proc or a block to `username` and `password` if you want to dynamically pull it from somewhere, e.g. a [Current class descending from ActiveSupport::CurrentAttributes](http://edgeapi.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html).
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
class Person < Flexirest::Base
|
20
|
+
username -> (obj) { obj ? Account.find(obj.id).username : Current.username }
|
21
|
+
password do
|
22
|
+
Rails.configuration.x.default_password
|
23
|
+
end
|
24
|
+
|
25
|
+
get :all, "/people"
|
26
|
+
get :find, "/people/:id"
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
In the above example, the `username` call handles things differently if it's called from an object context:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
person = Person.new(id: 1234)
|
34
|
+
person.find
|
35
|
+
```
|
36
|
+
|
37
|
+
Or if it's called from a class context:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
Person.find(id: 1234)
|
41
|
+
```
|
42
|
+
|
43
|
+
## Api-Auth
|
44
|
+
|
45
|
+
Using the [Api-Auth](https://github.com/mgomes/api_auth) integration it is very easy to sign requests. Include the Api-Auth gem in your `Gemfile` and then add it to your application. Then simply configure Api-Auth one time in your app and all requests will be signed from then on.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
require 'api-auth'
|
49
|
+
|
50
|
+
@access_id = '123456'
|
51
|
+
@secret_key = 'abcdef'
|
52
|
+
Flexirest::Base.api_auth_credentials(@access_id, @secret_key)
|
53
|
+
```
|
54
|
+
|
55
|
+
You can also specify different credentials for different models just like configuring `base_url`:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class Person < Flexirest::Base
|
59
|
+
api_auth_credentials '123456', 'abcdef'
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
For more information on how to generate an access id and secret key please read the [Api-Auth](https://github.com/mgomes/api_auth) documentation.
|
64
|
+
|
65
|
+
If you want to specify either the `:digest` or `:override_http_method` to ApiAuth, you can pass these in as options after the access ID and secret key, for example:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class Person < Flexirest::Base
|
69
|
+
api_auth_credentials '123456', 'abcdef', digest: "sha256"
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
|
74
|
+
-----
|
75
|
+
|
76
|
+
[< Lazy loading](lazy-loading.md) | [Body types >](body-types.md)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# *Flexirest:* Automatic conversion of fields to Date/DateTime
|
2
|
+
|
3
|
+
By default Flexirest will attempt to convert all fields to a `Date` or `DateTime` object if it's a string and the value matches certain regular expressions. However, on large responses this can be computationally expensive. You can disable this automatic conversion completely with:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
Flexirest::Base.disable_automatic_date_parsing = true
|
7
|
+
```
|
8
|
+
|
9
|
+
Additionally, you can specify when mapping the methods which fields should be parsed (so you can disable it in general, then apply it to particular known fields):
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Person < Flexirest::Base
|
13
|
+
get :all, '/people', parse_fields: [:created_at, :updated_at]
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
It is also possible to whitelist fields that should be parsed in your models, which is useful if you are instantiating these objects directly. The specified fields also apply automatically to request mapping.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class Person < Flexirest::Base
|
21
|
+
parse_date :updated_at, :created_at
|
22
|
+
end
|
23
|
+
|
24
|
+
# to disable all mapping
|
25
|
+
class Disabled < Flexirest::Base
|
26
|
+
parse_date :none
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
This system respects `disable_automatic_date_parsing`, and will default to mapping everything - unless a `parse_date` whitelist is specified, or automatic parsing is globally disabled.
|
31
|
+
|
32
|
+
-----
|
33
|
+
|
34
|
+
[< Per-request parameter encoding](per-request-parameter-encoding.md) | [Raw requests >](raw-requests.md)
|
data/docs/basic-usage.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# *Flexirest:* Basic usage
|
2
|
+
|
3
|
+
First you need to create your new model class `app/models/person.rb`:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Person < Flexirest::Base
|
7
|
+
base_url "https://www.example.com/api/v1"
|
8
|
+
|
9
|
+
get :all, "/people"
|
10
|
+
get :find, "/people/:id"
|
11
|
+
put :save, "/people/:id"
|
12
|
+
post :create, "/people"
|
13
|
+
delete :remove, "/people/:id"
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
Note I've specified the `base_url` in the class above. This is useful where you want to be explicit or use different APIs for some classes and be explicit. If you have one server that's generally used, you can set it once with a simple line in a `config/initializer/{something}.rb` file:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Flexirest::Base.base_url = "https://www.example.com/api/v1"
|
21
|
+
```
|
22
|
+
|
23
|
+
Any `base_url` settings in specific classes override this declared default. You can also assign an array of URLs to `base_url` and Flexirest will randomly pull one of the URLs for each request, giving you a very simplistic load balancing (it doesn't know about the health or load levels of the backends).
|
24
|
+
|
25
|
+
You can then use your new class like this:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# Create a new person
|
29
|
+
@person = Person.create(
|
30
|
+
first_name:"John"
|
31
|
+
last_name:"Smith"
|
32
|
+
)
|
33
|
+
|
34
|
+
# Find a person (not needed after creating)
|
35
|
+
id = @person.id
|
36
|
+
@person = Person.find(id)
|
37
|
+
|
38
|
+
# Update a person
|
39
|
+
@person.last_name = "Jones"
|
40
|
+
@person.save
|
41
|
+
|
42
|
+
# Get all people
|
43
|
+
@people = Person.all
|
44
|
+
@people.each do |person|
|
45
|
+
puts "Hi " + person.first_name
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
For `delete` requests whether an API can handle a body or not is undefined. The default is to ignore any parameters not sent in the URL named parameters, but you can optionally specify `send_delete_body` and it will encode them in your chosen way into the body.
|
50
|
+
|
51
|
+
```
|
52
|
+
delete :remove, "/people/:id", send_delete_body: true
|
53
|
+
```
|
54
|
+
|
55
|
+
If an API returns an array of results and you have [will_paginate](https://rubygems.org/gems/will_paginate) installed then you can call the paginate method to return a particular page of the results (note: this doesn't reduce the load on the server, but it can help with pagination if you have a cached response).
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
@people = Person.all
|
59
|
+
@people.paginate(page: 1, per_page: 10).each do |person|
|
60
|
+
puts "You made the first page: " + person.first_name
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
Note, you can assign to any attribute, whether it exists or not before and read from any attribute (which will return nil if not found). If you pass a string or a number to a method it will assume that it's for the "id" field. Any other field values must be passed as a hash and you can't mix passing a string/number and a hash.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
@person = Person.find(1234) # valid
|
68
|
+
@person = Person.find("1234") # valid
|
69
|
+
@person = Person.find(:id => 1234) # valid
|
70
|
+
@person = Person.find(:id => 1234, :name => "Billy") # valid
|
71
|
+
@person = Person.find(1234, :name => "Billy") # invalid
|
72
|
+
```
|
73
|
+
|
74
|
+
You can also call any mapped method as an instance variable which will pass the current attribute set in as parameters (either GET or POST depending on the mapped method type). If the method returns a single instance it will assign the attributes of the calling object and return itself. If the method returns a list of instances, it will only return the list. So, we could rewrite the create call above as:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
@person = Person.new
|
78
|
+
@person.first_name = "John"
|
79
|
+
@person.last_name = "Smith"
|
80
|
+
@person.create
|
81
|
+
puts @person.id
|
82
|
+
```
|
83
|
+
|
84
|
+
The response of the #create call set the attributes at that point (any manually set attributes before that point are removed).
|
85
|
+
|
86
|
+
If you have attributes beginning with a number, Ruby doesn't like this. So, you can use hash style notation to read/write the attributes:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
@tv = Tv.find(model:"UE55U8000") # { "properties" : {"3d" : false} }
|
90
|
+
puts @tv.properties["3d"]
|
91
|
+
@tv.properties["3d"] = true
|
92
|
+
```
|
93
|
+
|
94
|
+
If you want to debug the response, using inspect on the response object may well be useful. However, if you want a simpler output, then you can call `#to_json` on the response object:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
@person = Person.find(email:"something@example.com")
|
98
|
+
puts @person.to_json
|
99
|
+
```
|
100
|
+
|
101
|
+
-----
|
102
|
+
|
103
|
+
[< Introduction](../README.md) | [Ruby on Rails integration >](ruby-on-rails-integration.md)
|
data/docs/body-types.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# *Flexirest:* Body types
|
2
|
+
|
3
|
+
By default Flexirest formats the request bodies as normal CGI parameters in `K=V&K2=V2` format. However, if you want to use JSON for your PUT/POST requests, you can use choose to configure Flexirest to do so (the other option, the default, is `:form_encoded`):
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Person < Flexirest::Base
|
7
|
+
request_body_type :json
|
8
|
+
# ...
|
9
|
+
end
|
10
|
+
```
|
11
|
+
|
12
|
+
or
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
Flexirest::Base.request_body_type = :json
|
16
|
+
```
|
17
|
+
|
18
|
+
This will also set the header `Content-Type` to `application/x-www-form-urlencoded` by default or `application/json; charset=utf-8` when `:json`. You can override this using the callback `before_request`.
|
19
|
+
|
20
|
+
If you have an API that is inconsistent in its body type requirements, you can also specify it on the individual method mapping:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class Person < Flexirest::Base
|
24
|
+
request_body_type :form_encoded # This is the default, but just for demo purposes
|
25
|
+
|
26
|
+
get :all, '/people', request_body_type: :json
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
|
31
|
+
-----
|
32
|
+
|
33
|
+
[< Authentication](authentication.md) | [Parallel requests >](parallel-requests.md)
|
data/docs/caching.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# *Flexirest:* Caching
|
2
|
+
|
3
|
+
Expires and ETag based caching is enabled by default, but with a simple line in the application.rb/production.rb you can disable it:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
Flexirest::Base.perform_caching = false
|
7
|
+
```
|
8
|
+
|
9
|
+
or you can disable it per classes with:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Person < Flexirest::Base
|
13
|
+
perform_caching false
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
If Rails is defined, it will default to using Rails.cache as the cache store, if not, you'll need to configure one with a `ActiveSupport::Cache::Store` compatible object using:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Flexirest::Base.cache_store = Redis::Store.new("redis://localhost:6379/0/cache")
|
21
|
+
```
|
22
|
+
|
23
|
+
|
24
|
+
-----
|
25
|
+
|
26
|
+
[< Combined example](combined-example.md) | [Using callbacks >](using-callbacks.md)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# *Flexirest:* Combined example
|
2
|
+
|
3
|
+
OK, so let's say you have an API for getting articles. Each article has a property called `title` (which is a string) and a property `images` which includes a list of URIs. Following this URI would take you to a image API that returns the image's `filename` and `filesize`. We'll also assume this is a HAL compliant API. We would declare our two models (one for articles and one for images) like the following:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Article < Flexirest::Base
|
7
|
+
get :find, '/articles/:id', has_many:{:images => Image} # ,lazy:[:images] isn't needed as we're using HAL
|
8
|
+
end
|
9
|
+
|
10
|
+
class Image < Flexirest::Base
|
11
|
+
# You may have mappings here
|
12
|
+
|
13
|
+
def nice_size
|
14
|
+
"#{size/1024}KB"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
We assume the /articles/:id call returns something like the following:
|
20
|
+
|
21
|
+
```json
|
22
|
+
{
|
23
|
+
"title": "Fly Fishing",
|
24
|
+
"author": "J R Hartley",
|
25
|
+
"images": [
|
26
|
+
"http://api.example.com/images/1",
|
27
|
+
"http://api.example.com/images/2"
|
28
|
+
]
|
29
|
+
}
|
30
|
+
```
|
31
|
+
|
32
|
+
We said above that the /images/:id call would return something like:
|
33
|
+
|
34
|
+
```json
|
35
|
+
{
|
36
|
+
"filename": "http://cdn.example.com/images/foo.jpg",
|
37
|
+
"filesize": 123456
|
38
|
+
}
|
39
|
+
```
|
40
|
+
|
41
|
+
When it comes time to use it, you would do something like this:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
@article = Article.find(1)
|
45
|
+
@article.images.is_a?(Flexirest::LazyAssociationLoader)
|
46
|
+
@article.images.size == 2
|
47
|
+
@article.images.each do |image|
|
48
|
+
puts image.inspect
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
At this point, only the HTTP call to '/articles/1' has been made. When you actually start using properties of the images list/image object then it makes a call to the URL given in the images list and you can use the properties as if it was a nested JSON object in the original response instead of just a URL:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
@image = @article.images.first
|
56
|
+
puts @image.filename
|
57
|
+
# => http://cdn.example.com/images/foo.jpg
|
58
|
+
puts @image.filesize
|
59
|
+
# => 123456
|
60
|
+
```
|
61
|
+
|
62
|
+
You can also treat `@image` looks like an Image class (and you should 100% treat it as one) it's technically a lazy loading proxy. So, if you cache the views for your application should only make HTTP API requests when actually necessary.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
puts @image.nice_size
|
66
|
+
# => 121KB
|
67
|
+
```
|
68
|
+
|
69
|
+
|
70
|
+
-----
|
71
|
+
|
72
|
+
[< Associations](associations.md) | [Caching >](caching.md)
|
data/docs/debugging.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# *Flexirest:* Debugging
|
2
|
+
|
3
|
+
You can turn on verbose debugging to see what is sent to the API server and what is returned in one of these two ways:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Article < Flexirest::Base
|
7
|
+
verbose true
|
8
|
+
end
|
9
|
+
|
10
|
+
class Person < Flexirest::Base
|
11
|
+
verbose!
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
By default verbose logging isn't enabled, so it's up to the developer to enable it (and remember to disable it afterwards). It does use debug level logging, so it shouldn't fill up a correctly configured production server anyway.
|
16
|
+
|
17
|
+
If you prefer to record the output of an API call in a more automated fashion you can use a callback called `record_response` like this:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class Article < Flexirest::Base
|
21
|
+
record_response do |url, response|
|
22
|
+
File.open(url.parameterize, "w") do |f|
|
23
|
+
f << response.body
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
-----
|
31
|
+
|
32
|
+
[< Filtering result lists](filtering-result-lists.md) | [XML responses >](xml-responses.md)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# *Flexirest:* Default parameters
|
2
|
+
|
3
|
+
If you want to specify default parameters you shouldn't use a path like:
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Person < Flexirest::Base
|
7
|
+
get :all, '/people?all=true' # THIS IS WRONG!!!
|
8
|
+
end
|
9
|
+
```
|
10
|
+
|
11
|
+
You should use a defaults option to specify the defaults, then they will be correctly overwritten when making the request
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class Person < Flexirest::Base
|
15
|
+
get :all, '/people', :defaults => {:active => true}
|
16
|
+
end
|
17
|
+
|
18
|
+
@people = Person.all(active:false)
|
19
|
+
```
|
20
|
+
|
21
|
+
If you specify `defaults` as a `Proc` this will be executed with the set parameters (which you can change). For example to allow you to specify a reference (but the API wants it formated as "id-reference") you could use:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class Person < Flexirest::Base
|
25
|
+
get :all, "/", defaults: (Proc.new do |params|
|
26
|
+
reference = params.delete(:reference) # Delete the old parameter
|
27
|
+
{
|
28
|
+
id: "id-#{reference}"
|
29
|
+
} # The last thing is the hash of defaults
|
30
|
+
end)
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
|
35
|
+
-----
|
36
|
+
|
37
|
+
[< Translating APIs](translating-apis.md) | [Root elements >](root-elements.md)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# *Flexirest:* Faking calls
|
2
|
+
|
3
|
+
There are times when an API hasn't been developed yet, so you want to fake the API call response. To do this, you can simply pass a `:fake` option when mapping the call containing the response.
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Person < Flexirest::Base
|
7
|
+
get :all, '/people', fake: [{first_name:"Johnny"}, {first_name:"Bob"}]
|
8
|
+
end
|
9
|
+
```
|
10
|
+
|
11
|
+
You may want to run a proc when faking data (to put information from the parameters in to the response or return different responses depending on the parameters). To do this just pass a proc to `:fake`:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
class Person < Flexirest::Base
|
15
|
+
get :all, '/people', fake: ->(request) { {result: request.get_params[:id]} }
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
|
20
|
+
-----
|
21
|
+
|
22
|
+
[< Parallel requests](parallel-requests.md) | [Per-request timeouts >](per-request-timeouts.md)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# *Flexirest:* Faraday configuration
|
2
|
+
|
3
|
+
Flexirest uses Faraday to allow switching HTTP backends, the default is to just use Faraday's default. To change the used backend just set it in the class by setting `adapter` to a Faraday supported adapter symbol.
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
Flexirest::Base.adapter = :net_http
|
7
|
+
# or ...
|
8
|
+
Flexirest::Base.adapter = :patron
|
9
|
+
```
|
10
|
+
|
11
|
+
In versions before 1.2.0 the adapter was hardcoded to `:patron`, so if you want to ensure it still uses Patron, you should set this setting.
|
12
|
+
|
13
|
+
If you want more control you can pass a **complete** configuration block ("complete" means that the block does not _override_ [the default configuration](https://github.com/flexirest/flexirest/blob/5b1953d89e26c02ca74f74464ccb7cd4c9439dcc/lib/flexirest/configuration.rb#L184-L201), but rather _replaces_ it).
|
14
|
+
|
15
|
+
For available configuration variables look into the [Faraday documentation](https://github.com/lostisland/faraday).
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
Flexirest::Base.faraday_config do |faraday|
|
19
|
+
faraday.adapter(:net_http)
|
20
|
+
faraday.options.timeout = 10
|
21
|
+
faraday.headers['User-Agent'] = "Flexirest/#{Flexirest::VERSION}"
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
|
26
|
+
-----
|
27
|
+
|
28
|
+
[< Ruby on Rails integration](ruby-on-rails-integration.md) | [Associations >](associations.md)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# *Flexirest:* Filtering result lists
|
2
|
+
|
3
|
+
If the API returns a JSON list of items, this is retured to you as a `Flexirest::ResultIterator` object. A `ResultIterator` sorts simple filtering of the list using a `where` method based on values matching a specified criteria (or matching using regular expressions):
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
class Article < Flexirest::Base
|
7
|
+
get :all, "/articles"
|
8
|
+
end
|
9
|
+
|
10
|
+
Article.all.where(published: true, department: /technical\-/)
|
11
|
+
```
|
12
|
+
|
13
|
+
|
14
|
+
-----
|
15
|
+
|
16
|
+
[< Validation](validation.md) | [Debugging >](debugging.md)
|