flexirest 1.6.5 → 1.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +92 -1243
  4. data/docs/associations.md +181 -0
  5. data/docs/authentication.md +76 -0
  6. data/docs/automatic-conversion-of-fields-to-datedatetime.md +34 -0
  7. data/docs/basic-usage.md +103 -0
  8. data/docs/body-types.md +33 -0
  9. data/docs/caching.md +26 -0
  10. data/docs/combined-example.md +72 -0
  11. data/docs/debugging.md +32 -0
  12. data/docs/default-parameters.md +37 -0
  13. data/docs/faking-calls.md +22 -0
  14. data/docs/faraday-configuration.md +28 -0
  15. data/docs/filtering-result-lists.md +16 -0
  16. data/docs/httpparse-error-handling.md +17 -0
  17. data/{CONTRIBUTING.md → docs/internals.md} +4 -6
  18. data/docs/json-api.md +42 -0
  19. data/docs/lazy-loading.md +31 -0
  20. data/{Migrating-from-ActiveRestClient.md → docs/migrating-from-activerestclient.md} +2 -2
  21. data/docs/parallel-requests.md +28 -0
  22. data/docs/per-request-parameter-encoding.md +32 -0
  23. data/docs/per-request-timeouts.md +13 -0
  24. data/docs/plain-requests.md +30 -0
  25. data/docs/proxying-apis.md +86 -0
  26. data/docs/raw-requests.md +38 -0
  27. data/docs/required-parameters.md +17 -0
  28. data/docs/root-elements.md +34 -0
  29. data/{Ruby-on-Rails-Integration.md → docs/ruby-on-rails-integration.md} +16 -12
  30. data/docs/{Flexirest Internals.graffle → source/Flexirest Internals.graffle} +0 -0
  31. data/docs/{Flexirest Logo.sketch → source/Flexirest Logo.sketch} +0 -0
  32. data/docs/translating-apis.md +31 -0
  33. data/docs/updating-only-changed-dirty-attributes.md +37 -0
  34. data/docs/using-callbacks.md +114 -0
  35. data/docs/validation.md +89 -0
  36. data/docs/xml-responses.md +58 -0
  37. data/lib/flexirest/configuration.rb +36 -20
  38. data/lib/flexirest/request.rb +12 -4
  39. data/lib/flexirest/version.rb +1 -1
  40. data/spec/lib/request_spec.rb +28 -0
  41. metadata +35 -7
@@ -0,0 +1,17 @@
1
+ # *Flexirest:* HTTP/parse error handling
2
+
3
+ Sometimes the backend server may respond with a non-200/304 header, in which case the code will raise an `Flexirest::HTTPClientException` for 4xx errors or an `Flexirest::HTTPServerException` for 5xx errors. These both have a `status` accessor and a `result` accessor (for getting access to the parsed body):
4
+
5
+ ```ruby
6
+ begin
7
+ Person.all
8
+ rescue Flexirest::HTTPClientException, Flexirest::HTTPServerException => e
9
+ Rails.logger.error("API returned #{e.status} : #{e.result.message}")
10
+ end
11
+ ```
12
+
13
+ If the response is unparsable (e.g. not in the desired content type), then it will raise an `Flexirest::ResponseParseException` which has a `status` accessor for the HTTP status code and a `body` accessor for the unparsed response body.
14
+
15
+ -----
16
+
17
+ [< Updating only changed/dirty attributes](updating-only-changed-dirty-attributes.md) | [Validation >](validation.md)
@@ -1,19 +1,17 @@
1
- # Flexirest (ARC) Contributing Guide
1
+ # *Flexirest:* Internals of Flexirest
2
2
 
3
3
  ## Introduction
4
4
 
5
- This project was built at Which? Ltd in the UK as ActiveRestClient, but was released as open source in 2014 under the MIT Licence. This is Andy Jeffries' fork of the project as the original seems not to be maintained by Which? and there's been no communication back about the project.
6
-
7
5
  We're happy to receive contributions from the community for features and bugfixes and hopefully this guide helps new developers to the project to understand how to get started with the internals of Flexirest.
8
6
 
9
7
  ## Overview
10
8
 
11
- ![Component Overview Diagram](https://raw.githubusercontent.com/andyjeffries/flexirest/master/docs/Flexirest%20Internals.png)
9
+ ![Component Overview Diagram](Flexirest%20Internals.png)
12
10
 
13
11
  ## Components
14
12
 
15
13
  ### Base
16
- The main class in ARC is `Flexirest::Base`. This includes a number of modules to provide a basic object ready to inherit from to form your own API classes.
14
+ The main class in Flexirest is `Flexirest::Base`. This includes a number of modules to provide a basic object ready to inherit from to form your own API classes.
17
15
 
18
16
  **Configuration** includes all of the functionality for class and library level configuration (base_url, verbose logging, request format, etc).
19
17
 
@@ -33,7 +31,7 @@ This is a simple class that either uses a plain text file or Rails' logger if be
33
31
 
34
32
  ### Connection Manager/Connection
35
33
 
36
- The principle is that ARC keeps a cached `Connection` to each unique API server and these are kept open using [persistent connections](https://en.wikipedia.org/wiki/HTTP_persistent_connection). The connection for a given `base_url` is created or retrieved from the pool by the `ConnectionManager`.
34
+ The principle is that Flexirest keeps a cached `Connection` to each unique API server and these are kept open using [persistent connections](https://en.wikipedia.org/wiki/HTTP_persistent_connection). The connection for a given `base_url` is created or retrieved from the pool by the `ConnectionManager`.
37
35
 
38
36
  ### Request
39
37
 
data/docs/json-api.md ADDED
@@ -0,0 +1,42 @@
1
+ # *Flexirest:* JSON API
2
+
3
+ If you are working with a [JSON API](http://jsonapi.org), you need to activate JSON API by specifying the `json_api` proxy:
4
+
5
+ ```ruby
6
+ class Article < Flexirest::Base
7
+ proxy :json_api
8
+ end
9
+ ```
10
+
11
+ This proxy translates requests according to the JSON API specifications, parses responses, and retrieves linked resources. It also adds the `Accept: application/vnd.api+json` header for all requests.
12
+
13
+ It supports lazy loading by default. Unless a compound document is returned from the connected JSON API service, it will make another request to the service for the specified linked resource.
14
+
15
+ To reduce the number of requests to the service, you can ask the service to include the linked resources in the response. Such responses are called "compound documents". To do this, use the `includes` method:
16
+
17
+ ```ruby
18
+ # Makes a call to /articles with parameters: include=images
19
+ Article.includes(:images).all
20
+
21
+ # For nested resources, the include parameter becomes: include=images.tags,images.photographer
22
+ Article.includes(:images => [:tags, :photographer]).all
23
+ ```
24
+
25
+ For POST and PATCH requests, the proxy formats a JSON API compliant request, and adds a `Content-Type: application/vnd.api+json` header. It guesses the `type` value in the resource object from the class name, but it can be set specifically with `alias_type`:
26
+
27
+ ```ruby
28
+ class Photographer < Flexirest::Base
29
+ proxy :json_api
30
+ # Sets the type in the resource object to "people"
31
+ alias_type :people
32
+
33
+ patch :update, '/photographers/:id'
34
+ end
35
+ ```
36
+
37
+ NB: Updating relationships is not yet supported.
38
+
39
+
40
+ -----
41
+
42
+ [< Plain requests](plain-requests.md) | [Proxying APIs >](proxying-apis.md)
@@ -0,0 +1,31 @@
1
+ # *Flexirest:* Lazy loading
2
+
3
+ Flexirest supports lazy loading (delaying the actual API call until the response is actually used, so that views can be cached without still causing API calls).
4
+
5
+ **Note: Currently this isn't enabled by default, but this is likely to change in the future to make lazy loading the default.**
6
+
7
+ To enable it, simply call the lazy_load! method in your class definition:
8
+
9
+ ```ruby
10
+ class Article < Flexirest::Base
11
+ lazy_load!
12
+ end
13
+ ```
14
+
15
+ If you have a ResultIterator that has multiple objects, each being lazy loaded or HAL linked resources that isn't loaded until it's used, you can actually parallelise the fetching of the items using code like this:
16
+
17
+ ```ruby
18
+ items.parallelise(:id)
19
+
20
+ # or
21
+
22
+ items.parallelise do |item|
23
+ item.id
24
+ end
25
+ ```
26
+
27
+ This will return an array of the named method for each object or the response from the block and will have loaded the objects in to the resource.
28
+
29
+ -----
30
+
31
+ [< Using callbacks](using-callbacks.md) | [Authentication >](authentication.md)
@@ -1,4 +1,4 @@
1
- # Migrating from ActiveRestClient
1
+ # *Flexirest:* Migrating from ActiveRestClient
2
2
 
3
3
  While contracting at Which? Ltd I wrote a library in Ruby to access REST APIs in a very flexible, almost ActiveRecord style. This was agreed (after long discussions with the legal department) to be released as open source.
4
4
 
@@ -30,4 +30,4 @@ The second step is to find and replace across your codebase all instances of `Ac
30
30
 
31
31
  The third and final step is to clear your Rails cache. The easiest way of doing this is to type `Rails.cache.clear` in a Rails console.
32
32
 
33
- That's it, you've now switched over to Flexirest with a)lots of bug fixes, b)support for PATCH requests and c)someone actively continuing to support it!
33
+ That's it, you've now switched over to Flexirest with a)lots of bug fixes, b)support for PATCH requests and c)someone actively continuing to support it!
@@ -0,0 +1,28 @@
1
+ # *Flexirest:* Parallel requests
2
+
3
+ Sometimes you know you will need to make a bunch of requests and you don't want to wait for one to finish to start the next. When using parallel requests there is the potential to finish many requests all at the same time taking only as long as the single longest request. To use parallel requests you will need to set Flexirest to use a Faraday adapter that supports parallel requests [(such as Typhoeus)](https://github.com/lostisland/faraday/wiki/Parallel-requests).
4
+
5
+ ```ruby
6
+ # Set adapter to Typhoeus to use parallel requests
7
+ Flexirest::Base.adapter = :typhoeus
8
+ ```
9
+
10
+ Now you just need to get ahold of the connection that is going to make the requests by specifying the same host that the models will be using. When inside the `in_parallel` block call request methods as usual and access the results after the `in_parallel` block ends.
11
+
12
+ ```ruby
13
+ Flexirest::ConnectionManager.in_parallel('https://www.example.com') do
14
+ @person = Person.find(1234)
15
+ @employers = Employer.all
16
+
17
+ puts @person #=> nil
18
+ puts @employers #=> nil
19
+ end # The requests are all fired in parallel during this end statement
20
+
21
+ puts @person.name #=> "John"
22
+ puts @employers.size #=> 7
23
+ ```
24
+
25
+
26
+ -----
27
+
28
+ [< Body types](body-types.md) | [Faking calls >](faking-calls.md)
@@ -0,0 +1,32 @@
1
+ # *Flexirest:* Per-request parameter encoding
2
+
3
+ When URL-encoding GET parameters, Rudy adds brackets(`[]`) by default to any parameters in an `Array`. For example, if you tried to pass these parameters:
4
+
5
+ ```ruby
6
+ Person.all(param: [1, 2, 3])
7
+ ```
8
+
9
+ Ruby would encode the URL as
10
+
11
+ ```
12
+ ?param[]=1&param[]=2&param[]=3
13
+ ```
14
+
15
+ If you prefer flattened notation instead, pass a `params_encoder` option of `:flat` when mapping the call. So this call:
16
+
17
+ ```ruby
18
+ class Person < Flexirest::Base
19
+ get :all, '/people', params_encoder: :flat
20
+ end
21
+ ```
22
+
23
+ would output the following URL:
24
+
25
+ ```
26
+ ?param=1&param=2&param=3
27
+ ```
28
+
29
+
30
+ -----
31
+
32
+ [< Per-request timeouts](per-request-timeouts.md) | [Automatic conversion of fields to Date/DateTime >](automatic-conversion-of-fields-to-datedatetime.md)
@@ -0,0 +1,13 @@
1
+ # *Flexirest:* Per-request timeouts
2
+
3
+ There are times when an API is generally quick, but one call is very intensive. You don't want to set a global timeout in the Faraday configuration block, you just want to increase the timeout for this single call. To do this, you can simply pass a `timeout` option when mapping the call containing the response (in seconds).
4
+
5
+ ```ruby
6
+ class Person < Flexirest::Base
7
+ get :all, '/people', timeout: 5
8
+ end
9
+ ```
10
+
11
+ -----
12
+
13
+ [< Faking calls](faking-calls.md) | [Per-request parameter encoding >](per-request-parameter-encoding.md)
@@ -0,0 +1,30 @@
1
+ # *Flexirest:* Plain requests
2
+
3
+ If you are already using Flexirest but then want to simply call a normal URL and receive the resulting content as a string (i.e. not going through JSON parsing or instantiating in to a `Flexirest::Base` descendent) you can use code like this:
4
+
5
+ ```ruby
6
+ class Person < Flexirest::Base
7
+ end
8
+
9
+ people = Person._plain_request('http://api.example.com/v1/people') # Defaults to get with no parameters
10
+ # people is a normal Flexirest object, implementing iteration, HAL loading, etc.
11
+
12
+ Person._plain_request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
13
+ ```
14
+
15
+ The parameters are the same as for `_request`, but it does no parsing on the response
16
+
17
+ You can also bypass the response parsing using a mapped method like this:
18
+
19
+ ```ruby
20
+ class Person < Flexirest::Base
21
+ get :all, "/v1/people", plain: true
22
+ end
23
+ ```
24
+
25
+ The response of a plain request (from either source) is a `Flexirest::PlainResponse` which acts like a string containing the response's body, but it also has a `_headers` method that returns the HTTP response headers and a `_status` method containing the response's HTTP method.
26
+
27
+
28
+ -----
29
+
30
+ [< Raw requests](raw-requests.md) | [JSON API >](json-api.md)
@@ -0,0 +1,86 @@
1
+ # *Flexirest:* Proxying APIs
2
+
3
+ Sometimes you may be working with an old API that returns JSON in a less than ideal format or the URL or parameters required have changed.
4
+
5
+ If it's simply that you want attribute names like `SomeName` or `someName` to be more Ruby-style `some_name` then you can simply do that by setting `:rubify_names` when mapping an API call.
6
+
7
+ ```ruby
8
+ class Article < Flexirest::Base
9
+ base_url "http://www.example.com"
10
+
11
+ get :all, "/all", rubify_names: true
12
+ end
13
+ ```
14
+
15
+ In more complex cases you can define a descendent of `Flexirest::ProxyBase`, pass it to your model as the proxy and have it rework URLs/parameters on the way out and the response on the way back in (already converted to a Ruby hash/array). By default any non-proxied URLs are just passed through to the underlying connection layer. For example:
16
+
17
+ ```ruby
18
+ class ArticleProxy < Flexirest::ProxyBase
19
+ get "/all" do
20
+ url "/all_people" # Equiv to url.gsub!("/all", "/all_people") if you wanted to keep params
21
+ response = passthrough
22
+ translate(response) do |body|
23
+ body["first_name"] = body.delete("fname")
24
+ body
25
+ end
26
+ end
27
+ end
28
+
29
+ class Article < Flexirest::Base
30
+ proxy ArticleProxy
31
+ base_url "http://www.example.com"
32
+
33
+ get :all, "/all", fake:"{\"name\":\"Billy\"}"
34
+ get :list, "/list", fake:"[{\"name\":\"Billy\"}, {\"name\":\"John\"}]"
35
+ end
36
+
37
+ Article.all.first_name == "Billy"
38
+ ```
39
+
40
+ This example does two things:
41
+
42
+ 1. It rewrites the incoming URL for any requests matching "_/all_" to "/all_people"
43
+ 2. It uses the `translate` method to move the "fname" attribute from the response body to be called "first_name". The translate method must return the new object at the end (either the existing object alterered, or a new object to replace it with)
44
+
45
+ As the comment shows, you can use `url value` to set the request URL to a particular value, or you can call `gsub!` on the url to replace parts of it using more complicated regular expressions.
46
+
47
+ You can use the `get_params` or `post_params` methods within your proxy block to amend/create/delete items from those request parameters, like this:
48
+
49
+ ```ruby
50
+ get "/list" do
51
+ get_params["id"] = get_params.delete("identifier")
52
+ passthrough
53
+ end
54
+ ```
55
+
56
+ This example renames the get_parameter for the request from `identifier` to `id` (the same would have worked with post_params if it was a POST/PUT request). The `passthrough` method will take care of automatically recombining them in to the URL or encoding them in to the body as appropriate.
57
+
58
+ If you want to manually set the body for the API yourself you can use the `body` method
59
+
60
+ ```ruby
61
+ put "/update" do
62
+ body "{\"id\":#{post_params["id"]}}"
63
+ passthrough
64
+ end
65
+ ```
66
+
67
+ This example takes the `post_params["id"]` and converts the body from being a normal form-encoded body in to being a JSON body.
68
+
69
+ The proxy block expects one of three things to be the return value of the block.
70
+
71
+ 1. The first options is that the call to `passthrough` is the last thing and it calls down to the connection layer and returns the actual response from the server in to the "API->Object" mapping layer ready for use in your application
72
+ 2. The second option is to save the response from `passthrough` and use `translate` on it to alter the structure.
73
+ 3. The third option is to use `render` if you want to completely fake an API and return the JSON yourself
74
+
75
+ To completely fake the API, you can do the following. Note, this is also achievable using the `fake` setting when mapping a method, however by doing it in a Proxy block means you can dynamically generate the JSON rather than just a hard coded string.
76
+
77
+ ```ruby
78
+ put "/fake" do
79
+ render "{\"id\":1234}"
80
+ end
81
+ ```
82
+
83
+
84
+ -----
85
+
86
+ [< JSON API](json-api.md) | [Translating APIs >](translating-apis.md)
@@ -0,0 +1,38 @@
1
+ # *Flexirest:* Raw requests
2
+
3
+ Sometimes you have have a URL that you just want to force through, but have the response handled in the same way as normal objects or you want to have the callbacks run (say for authentication). The easiest way to do that is to call `_request` on the class:
4
+
5
+ ```ruby
6
+ class Person < Flexirest::Base
7
+ end
8
+
9
+ people = Person._request('http://api.example.com/v1/people') # Defaults to get with no parameters
10
+ # people is a normal Flexirest object, implementing iteration, HAL loading, etc.
11
+
12
+ Person._request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
13
+ ```
14
+
15
+ When you need to specify custom headers (for example for authentication) you can do this with a fourth option to the `_request` method. If you are using the default paramaters you'll need to specify them. For example:
16
+
17
+ ```ruby
18
+ Person._request("http://api.example.com/v1/people", :get, {}, {headers:{"X-Something": "foo/bar"}})
19
+ ```
20
+
21
+ If you want to use a lazy loaded request instead (so it will create an object that will only call the API if you use it), you can use `_lazy_request` instead of `_request`. If you want you can create a construct that creates and object that lazy loads itself from a given method (rather than a URL):
22
+
23
+ ```ruby
24
+ @person = Person._lazy_request(Person._request_for(:find, 1234))
25
+ ```
26
+
27
+ This initially creates a `Flexirest::Request` object as if you'd called `Person.find(1234)` which is then passed in to the `_lazy_request` method to return an object that will call the request if any properties are actually used. This may be useful at some point, but it's actually easier to just prefix the `find` method call with `lazy_` like:
28
+
29
+ ```ruby
30
+ @person = Person.lazy_find(1234)
31
+ ```
32
+
33
+ Doing this will try to find a literally mapped method called "lazy_find" and if it fails, it will try to use "find" but instantiate the object lazily.
34
+
35
+
36
+ -----
37
+
38
+ [< Automatic conversion of fields to Date/DateTime](automatic-conversion-of-fields-to-datedatetime.md) | [Plain requests >](plain-requests.md)
@@ -0,0 +1,17 @@
1
+ # *Flexirest:* Required parameters
2
+
3
+ If you want to specify that certain parameters are required for a specific call, you can specify them like:
4
+
5
+ ```ruby
6
+ class Person < Flexirest::Base
7
+ get :all, '/people', :requires => [:active]
8
+ end
9
+
10
+ @people = Person.all # raises Flexirest::MissingParametersException
11
+ @people = Person.all(active:false)
12
+ ```
13
+
14
+
15
+ -----
16
+
17
+ [< Root elements](root-elements.md) | [Updating only changed/dirty attributes >](updating-only-changed-dirty-attributes.md)
@@ -0,0 +1,34 @@
1
+ # *Flexirest:* Root elements
2
+
3
+ If your response comes back with a root node and you'd like to ignore it, you can define the mapping as:
4
+
5
+ ```ruby
6
+ class Feed < Flexirest::Base
7
+ post :list, "/feed", ignore_root: "feed"
8
+ end
9
+ ```
10
+
11
+ Alternatively if you want to wrap your JSON request body in a root element, e.g.:
12
+
13
+ ```json
14
+ {
15
+ "feed": {
16
+ "id": 1
17
+ }
18
+ }
19
+ ```
20
+
21
+ You can do it like this:
22
+
23
+ ```ruby
24
+ class Feed < Flexirest::Base
25
+ post :list, "/feed", wrap_root: "feed"
26
+ end
27
+
28
+ Feed.list(id: 1)
29
+ ```
30
+
31
+
32
+ -----
33
+
34
+ [< Default parameters](default-parameters.md) | [Required parameters >](required-parameters.md)
@@ -1,7 +1,6 @@
1
- # Ruby on Rails Integration
2
-
3
- Flexirest works fine with Ruby on Rails Framework. This guide was tested with a Rails 4.2.x Application.
1
+ # *Flexirest:* Ruby on Rails Integration
4
2
 
3
+ The author built Flexirest to use within Ruby on Rails, but it doesn't require full Ruby on Rails. This guide was tested with a Rails 4.2.x Application but also works fine with Rails 5.x.
5
4
 
6
5
  ## Integration
7
6
 
@@ -15,9 +14,9 @@ gem 'flexirest'
15
14
 
16
15
  ## Configuration
17
16
 
18
- It's possible to explicit specify the `base_url` in the Model Class. If you have an common API Endpoint it makes sense to setup an initializer in `config/initializers` or use the `Rails.application.configure` namespace.
17
+ It's possible to explicit specify the `base_url` in the model class. If you have an common API Endpoint it makes sense to setup an initializer in `config/initializers` or use the `Rails.configuration.x` namespace.
19
18
 
20
- This example use a custom file in `config/initializers` to setup the API endpoint. Either set a fixed URL or use environment variables if you would like to follow the [12factor](http://12factor.net/config) rules for preparing your application running on cloud infrastructure like heroku.
19
+ This example use a custom file in `config/initializers` to setup the API endpoint. Either set a fixed URL or use environment variables if you would like to follow the [12factor](http://12factor.net/config) rules for preparing your application running on cloud infrastructure like Heroku, Kubernetes or Docker Swarm.
21
20
 
22
21
  ```ruby
23
22
  # config/initializers/flexirest.rb
@@ -41,17 +40,19 @@ end
41
40
 
42
41
  ## Model
43
42
 
44
- The `ActiveModel` shortcuts will add support for `form_for` helper and `@person.errors` functionally in your views.
45
- For example, if you have a scaffolded view structure this will just work out of the box. Read more about `ActiveModel` here:
43
+ The `ActiveModel` shortcuts will add support for `form_for` helper and `@person.errors` functionally in your views. For example, if you have a scaffolded view structure this will just work out of the box.
44
+
45
+ Read more about `ActiveModel` here:
46
46
 
47
47
  * [ActiveModel::Naming](http://api.rubyonrails.org/classes/ActiveModel/Naming.html)
48
48
  * [ActiveModel::Conversion](http://api.rubyonrails.org/classes/ActiveModel/Conversion.html)
49
49
  * [ActiveModel::Validations](http://api.rubyonrails.org/classes/ActiveModel/Validations.html)
50
50
 
51
51
  In Rails, a resourceful route provides a mapping between HTTP verbs and URLs to controller actions.
52
+
52
53
  Add the GET, POST, PATCH and DELETE methods that reflect to your endpoint.
53
54
 
54
- Add the `persisted?` method to your Class to support Rails named_routes, so you could use `edit_person_path(person)` without explicit pass the `person.id`.
55
+ Add the `persisted?` method to your Class to support Rails' `named_routes`, so you could use `edit_person_path(person)` without explicitly passing the `person.id`.
55
56
 
56
57
 
57
58
  ```ruby
@@ -78,11 +79,9 @@ end
78
79
 
79
80
  ## Controller
80
81
 
81
- The Controller is structured like an standard RESTful Rails Controller. Only the `update` method has
82
- a small change about how params getting processed.
82
+ The Controller is structured like an standard RESTful Rails Controller. Only the `update` method has a small change about how params getting processed.
83
83
 
84
- Flexirest requires the `id` inside the params hash, this is not included by default.
85
- Easily merge the current id into the params with `person_params.merge(id: @person.id)`
84
+ Flexirest requires the `id` inside the params hash, this is not included by default. Easily merge the current `id` into the parameters with `person_params.merge(id: @person.id)`
86
85
 
87
86
  No other changes had to be made for the controller.
88
87
 
@@ -140,3 +139,8 @@ class PeopleController < ApplicationController
140
139
  end
141
140
  end
142
141
  ```
142
+
143
+
144
+ -----
145
+
146
+ [< Basic usage](basic-usage.md) | [Faraday configuration >](faraday-configuration.md)
@@ -0,0 +1,31 @@
1
+ # *Flexirest:* Translating APIS (DEPRECATED)
2
+
3
+ **IMPORTANT: This functionality has been deprecated in favour of the [Proxying APIs](proxying-apis.md) functionality. You should aim to remove this from your code as soon as possible.**
4
+
5
+ Sometimes you may be working with an API that returns JSON in a less than ideal format. In this case you can define a barebones class and pass it to your model. The Translator class must have class methods that are passed the JSON object and should return an object in the correct format. It doesn't need to have a method unless it's going to translate that mapping though (so in the example below there's no list method). For example:
6
+
7
+ ```ruby
8
+ class ArticleTranslator
9
+ def self.all(object)
10
+ ret = {}
11
+ ret["first_name"] = object["name"]
12
+ ret
13
+ end
14
+ end
15
+
16
+ class Article < Flexirest::Base
17
+ translator ArticleTranslator
18
+ base_url "http://www.example.com"
19
+
20
+ get :all, "/all", fake:"{\"name\":\"Billy\"}"
21
+ get :list, "/list", fake:"[{\"name\":\"Billy\"}, {\"name\":\"John\"}]"
22
+ end
23
+
24
+ Article.all.first_name == "Billy"
25
+ ```
26
+
27
+
28
+
29
+ -----
30
+
31
+ [< Proxying APIs](proxying-apis.md) | [Default parameters >](default-parameters.md)
@@ -0,0 +1,37 @@
1
+ # *Flexirest:* Updating only changed/dirty attributes
2
+
3
+ The most common RESTful usage of the PATCH http-method is to only send fields that have changed. The default action for all calls is to send all known object attributes for POST/PUT/PATCH calls, but this can be altered by setting the `only_changed` option on your call declaration.
4
+
5
+ ```ruby
6
+ class Person < Flexirest::Base
7
+ get :all, '/people'
8
+ patch :update, '/people/:id', :only_changed => true # only send attributes that are changed/dirty
9
+ end
10
+
11
+ person = Person.all.first
12
+ person.first_name = 'Billy'
13
+ person.update # performs a PATCH request, sending only the now changed 'first_name' attribute
14
+ ```
15
+
16
+ This functionality is per-call, and there is some additional flexibility to control which attributes are sent and when.
17
+
18
+ ```ruby
19
+ class Person < Flexirest::Base
20
+ get :all, '/people'
21
+ patch :update_1, '/people/:id', :only_changed => true # only send attributes that are changed/dirty (all known attributes on this object are subject to evaluation)
22
+ patch :update_2, "/people/:id", :only_changed => [:first_name, :last_name, :dob] # only send these listed attributes, and only if they are changed/dirty
23
+ patch :update_3, "/people/:id", :only_changed => {first_name: true, last_name: true, dob: false} # include the listed attributes marked 'true' only when changed; attributes marked 'false' are always included (changed or not, and if not present will be sent as nil); unspecified attributes are never sent
24
+ end
25
+ ```
26
+
27
+ #### Additional Notes:
28
+
29
+ - The above examples specifically showed PATCH methods, but this is also available for POST and PUT methods for flexibility purposes (even though they break typical REST methodology).
30
+ - This logic is currently evaluated before Required Parameters, so it is possible to ensure that requirements are met by some clever usage.
31
+
32
+ - This means that if a method is `:requires => [:active], :only_changed => {active: false}` then `active` will always have a value and would always pass the `:requires` directive (so you need to be very careful because the answer may end up being `nil` if you didn't specifically set it).
33
+
34
+
35
+ -----
36
+
37
+ [< Required parameters](required-parameters.md) | [HTTP/parse error handling >](httpparse-error-handling.md)