apicasso 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +226 -223
  3. data/Rakefile +23 -23
  4. data/app/controllers/apicasso/apidocs_controller.rb +309 -299
  5. data/app/controllers/apicasso/application_controller.rb +170 -147
  6. data/app/controllers/apicasso/crud_controller.rb +246 -245
  7. data/app/controllers/concerns/orderable.rb +45 -45
  8. data/app/models/apicasso/ability.rb +38 -38
  9. data/app/models/apicasso/application_record.rb +6 -6
  10. data/app/models/apicasso/key.rb +25 -25
  11. data/app/models/apicasso/request.rb +8 -8
  12. data/config/routes.rb +14 -14
  13. data/lib/apicasso/active_record_extension.rb +0 -44
  14. data/lib/apicasso/engine.rb +13 -13
  15. data/lib/apicasso/version.rb +3 -3
  16. data/lib/apicasso.rb +15 -13
  17. data/lib/generators/apicasso/install/install_generator.rb +25 -25
  18. data/lib/generators/apicasso/install/templates/create_apicasso_tables.rb +20 -20
  19. data/spec/dummy/Gemfile +56 -0
  20. data/spec/dummy/Gemfile.lock +237 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +1 -1
  22. data/spec/dummy/app/models/used_model.rb +42 -0
  23. data/spec/dummy/app/serializers/used_model_serializer.rb +3 -0
  24. data/spec/dummy/bin/rails +5 -0
  25. data/spec/dummy/bin/rake +5 -0
  26. data/spec/dummy/bin/setup +0 -3
  27. data/spec/dummy/bin/spring +17 -0
  28. data/spec/dummy/bin/update +0 -3
  29. data/spec/dummy/config/application.rb +14 -10
  30. data/spec/dummy/config/cable.yml +1 -1
  31. data/spec/dummy/config/credentials.yml.enc +1 -0
  32. data/spec/dummy/config/database.yml +5 -14
  33. data/spec/dummy/config/environments/development.rb +6 -10
  34. data/spec/dummy/config/environments/production.rb +1 -10
  35. data/spec/dummy/config/initializers/cors.rb +16 -0
  36. data/spec/dummy/config/locales/en.yml +7 -32
  37. data/spec/dummy/config/routes.rb +1 -1
  38. data/{db/migrate/20180826141433_create_apicasso_tables.rb → spec/dummy/db/migrate/20180918134607_create_apicasso_tables.rb} +1 -0
  39. data/spec/dummy/db/migrate/20180918141254_create_used_models.rb +44 -0
  40. data/spec/dummy/db/migrate/20180919130152_create_active_storage_tables.active_storage.rb +26 -0
  41. data/spec/dummy/db/migrate/20180920133933_change_used_model_to_validates.rb +7 -0
  42. data/spec/dummy/db/schema.rb +98 -0
  43. data/spec/dummy/db/seeds.rb +56 -0
  44. data/spec/factories/used_model.rb +28 -0
  45. data/spec/models/used_model_spec.rb +35 -0
  46. data/spec/rails_helper.rb +66 -0
  47. data/spec/requests/requests_spec.rb +227 -0
  48. data/spec/spec_helper.rb +7 -9
  49. data/spec/support/factory_bot.rb +3 -0
  50. metadata +83 -64
  51. data/spec/controllers/apicasso/aplication_controller_spec.rb +0 -18
  52. data/spec/controllers/apicasso/crud_controller_spec.rb +0 -107
  53. data/spec/dummy/app/assets/config/manifest.js +0 -3
  54. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  55. data/spec/dummy/app/assets/javascripts/cable.js +0 -13
  56. data/spec/dummy/app/assets/stylesheets/application.css +0 -15
  57. data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
  58. data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
  59. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  60. data/spec/dummy/app/jobs/application_job.rb +0 -2
  61. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  62. data/spec/dummy/app/views/layouts/application.html.erb +0 -15
  63. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  64. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  65. data/spec/dummy/bin/yarn +0 -11
  66. data/spec/dummy/config/initializers/assets.rb +0 -14
  67. data/spec/dummy/config/initializers/content_security_policy.rb +0 -25
  68. data/spec/dummy/config/initializers/cookies_serializer.rb +0 -5
  69. data/spec/dummy/log/development.log +0 -0
  70. data/spec/dummy/public/404.html +0 -67
  71. data/spec/dummy/public/422.html +0 -67
  72. data/spec/dummy/public/500.html +0 -66
  73. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  74. data/spec/dummy/public/apple-touch-icon.png +0 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/factories/apicasso_key.rb +0 -9
  77. data/spec/factories/object.rb +0 -5
  78. data/spec/models/apicasso/key.rb +0 -5
  79. data/spec/routing/appointments_routing_spec.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7add1947b0a0fb48f891fa6ddfb70a739fa96840
4
- data.tar.gz: a042f1dea08c37cda68fab6fb4de9e5222806b50
2
+ SHA256:
3
+ metadata.gz: 285f7a239620529fadc3773625ad7c03228443339ef2c730dccab9bc5974ae8b
4
+ data.tar.gz: 90e3ed224db4b180f3498dd9c3465d7c472f6f8c97ed3aeaf808e265a1d99600
5
5
  SHA512:
6
- metadata.gz: 9b5495b5500decdd880da4de7f2e4f175577a612eefdcd86dfe45a4913200127762993374887ad0ad4c1093e9ed2b1e0e889580c2a968ec10cb1b9880c283df7
7
- data.tar.gz: 586d67fc1be1cd253f6b609413fbf82f7927dfc23465aaedbea6efb2785c0d414cd5e91ca82b87f397f2704ce7f94ac66114b4a827f42ba0c60076eafe33fcfe
6
+ metadata.gz: 11af9ea91bffca509df5074001e47a6f0f0ae731efeac2f55100bc16126676edfe890bc73c424b2e81d0e925178a37653e0bdaf3a2748a3ef32100883f4eb83f
7
+ data.tar.gz: 307de7af6520e44516545fdbe757f0cfa3490053f8e386c257311dd5f267a89b98b45580981140e56bcf11000508c3d44f6720e864589fae8918e16eda4cdddf
data/README.md CHANGED
@@ -1,223 +1,226 @@
1
- <img src="https://raw.githubusercontent.com/ErvalhouS/APIcasso/master/APIcasso.png" width="300" /> [![Gem Version](https://badge.fury.io/rb/apicasso.svg)](https://badge.fury.io/rb/apicasso) [![Docs Coverage](https://inch-ci.org/github/autoforce/APIcasso.svg?branch=master)](https://inch-ci.org/github/autoforce/APIcasso.svg?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/b58bbd6b9a0376f7cfc8/maintainability)](https://codeclimate.com/github/autoforce/APIcasso/maintainability) [![codecov](https://codecov.io/gh/autoforce/APIcasso/branch/master/graph/badge.svg)](https://codecov.io/gh/autoforce/APIcasso) [![Build Status](https://travis-ci.org/autoforce/APIcasso.svg?branch=master)](https://travis-ci.org/autoforce/APIcasso)
2
-
3
- JSON API development can get boring and time consuming. If you think it through, every time you make one you use almost the same route structure, pointing to the same controller actions, with the same ordering, filtering and pagination features.
4
-
5
- **APIcasso** is intended to be used as a full-fledged CRUD JSON API or as a base controller to speed-up development.
6
- It is a route-based resource abstraction using API key scoping. This makes it possible to make CRUD-only applications just by creating functional Rails' models. It is a perfect candidate for legacy Rails projects that do not have an API. Access to your application's resources is managed by a `.scope` JSON object per API key. It uses that permission scope to restrict and extend access.
7
-
8
- # Installation
9
-
10
- Add this line to your application's `Gemfile`:
11
-
12
- ```ruby
13
- gem 'apicasso'
14
- ```
15
-
16
- And then execute this to generate the required migrations:
17
-
18
- ```bash
19
- $ bundle install && rails g apicasso:install
20
- ```
21
-
22
- ### You must have PostgreSQL as database to be able to use this gem.
23
-
24
- # Usage
25
-
26
- **APIcasso** is meant to be used as an engine, which means you don't need to configure any route or controller to build a working CRUD API. Sometimes you also need some customized controller actions or even a specific logic to access some of your application's resources. In that case you will use `Apicasso::CrudController` class to easily build only your own logic around the API abstraction.
27
-
28
- ## Mounting engine into `config/routes.rb`
29
-
30
- After installing it, you can mount a full-fledged CRUD JSON API just by attaching into some route. Usually you will have it under a scoped route like `/api/v1` or a subdomain. You can do that by adding this into your `config/routes.rb`:
31
-
32
- ```ruby
33
- # To mount your APIcasso routes under the path scope `/api/v1`
34
- mount Apicasso::Engine, at: "/api/v1"
35
- # or, if you prefer subdomain scope isolation
36
- constraints subdomain: 'apiv1' do
37
- mount Apicasso::Engine, at: "/"
38
- end
39
- ```
40
-
41
- Your API will reflect very similarly a `resources :resource` statement with the following routes:
42
-
43
- ```ruby
44
- get '/:resource/' # Index action, listing a `:resource` collection from your application
45
- post '/:resource/' # Create action for one `:resource` from your application
46
- get '/:resource/:id' # Show action for one `:resource` from your application
47
- patch '/:resource/:id' # Update action for one `:resource` from your application
48
- delete '/:resource/:id' # Destroy action for one `:resource` from your application
49
- get '/:resource/:id/:nested/' # Index action, listing a collection of a `:nested` relation from one of your application's `:resource`
50
- options '/:resource/' # A schema dump for the required `:resource`
51
- options '/:resource/:id/:nested/' # A schema dump for the required `:nested` relation from one of your application's `:resource`
52
- ```
53
-
54
- This means all your application's models will be exposed as `:resource` and it's relations will be exposed as `:nested`. It will enable you to CRUD and get schema metadata from your records.
55
-
56
- ## Extending base API actions
57
-
58
- When your application needs some kind of custom interaction that is not covered by APIcasso's CRUD approach you can make your own actions using our base classes and objects to go straight into your logic. If you have built the APIcasso's engine into a route it is important that your custom action takes precedence over the gem's ones. To do that you need to declare your custom route before the engine on you `config/routes.rb`
59
-
60
- ```ruby
61
- match '/:resource/:id/a-custom-action' => 'custom#not_a_crud', via: :get
62
- mount Apicasso::Engine, at: "/api/v1"
63
- ```
64
-
65
- And in your `app/controllers/custom_controller.rb` you would have something like:
66
-
67
- ```ruby
68
- class CustomController < Apicasso::CrudController
69
- def not_a_crud
70
- render json: @object.some_operation
71
- end
72
- end
73
- ```
74
-
75
- This way you enjoy all our object finder, authorization and authentication features, making your job more straight into your business logic.
76
-
77
- ## Authentication
78
-
79
- > But exposing my models to the internet is permissive as hell! Haven't you thought about security?
80
-
81
- _Sure!_ The **APIcasso** suite is exposing your application using authentication through `Authorization: Token` [HTTP header authentication](http://tools.ietf.org/html/draft-hammer-http-token-auth-01). The API key objects are manageable through the `Apicasso::Key` model, which gets setup at install. When a new key is created a `.token` is generated using an [Universally Unique Identifier(RFC 4122)](https://tools.ietf.org/html/rfc4122). A authenticated request looks like this:
82
-
83
- ```
84
- curl -X GET \
85
- https://apixample.com/v1/your_app_resource \
86
- -H 'authorization: Token token=cda4e9f633c123ef9ddce5e6564292b3'
87
- ```
88
-
89
- Each `Apicasso::Key` object has a token attribute, which is used on this header to authorize access. For now, there is no plans for a login/JWT logic, you should implement this in your project's scope.
90
-
91
- ## Authorization
92
-
93
- Your Models are then exposed based on each `Apicasso::Key.scope` definition, which is a way to configure how much of your application each key can access. I.E.:
94
-
95
- ```ruby
96
- Apicasso::Key.create(scope:
97
- { manage:
98
- { order: true, user: { account_id: 1 } },
99
- read:
100
- { account: { manager_id: 1 } }
101
- })
102
- ```
103
-
104
- > The key from this example will have full access to all orders and to users with `account_id == 1`. It will have also read-only access to accounts with `id == 1`.
105
-
106
- A scope configured like this translates directly into which kind of access each key has on all of your application's models. This kind of authorization is why one of the dependencies for this gem is [CanCanCan](https://github.com/CanCanCommunity/cancancan), which abstracts the scope field into your API access control.
107
-
108
- You can have two kind of access control:
109
-
110
- - `true` - This will mean the key will have the declared clearance on **ALL** of this model's records
111
- - `Hash` - This will build a condition to what records this key have access to. A scope as `{ read: [{ account: { manager_id: 1 } }] }` will have read access into accounts with `manager_id == 1`
112
-
113
- This saves you the trouble of having to setup every controller for each model. And even if your application really needs it, just make your controllers inherit from `Apicasso::CrudController` extending it and enabling the use of `@object` and `@resource` variables to access what is being resquested.
114
-
115
- ## Features on index actions
116
-
117
- The index actions present in the gem are already equipped with pagination, ordering, grouping, fieldset selection and filtering. This will save you a lot of trouble, adding some best-practices conventions into your application's API.
118
-
119
- ### Sort
120
-
121
- You can sort a collection query by using a URL parameter with field names preffixed with `+` or `-` to configure custom ordering per request.
122
-
123
- To order a collection with ascending `updated_at` and descending `name` you can add the `sort` parameter with those fields as options, indicating which kind of ordination you want to give to each one:
124
-
125
- ```
126
- ?sort=+updated_at,-name
127
- ```
128
-
129
- ### Filtering/Search
130
-
131
- APIcasso has [ransack's search matchers](https://github.com/activerecord-hackery/ransack#search-matchers) on it's index actions. This means you can dynamically build search queries with any of your resource's fields, this will be done by using a `?q` parameter which groups all your filtering options on your requests. If you wanted to search all your records and return only the ones with `full_name` starting with `Picasso` your query would look something like this:
132
-
133
- ```
134
- ?q[full_name_start]=Picasso
135
- ```
136
-
137
- To build complex search queries you can chain many parameter options or check [ransack's wiki](https://github.com/activerecord-hackery/ransack/wiki/) on how to adapt this feature into your project's needs.
138
-
139
- ### Pagination
140
-
141
- Automatic pagination is done in index actions, with the adittion of some metadata to help on the data consumption. You can pass page and per page parameters to build pagination options into your needs. And on requests that you need unpaginated collections, just pass a lower than zero `per_page`. Example of a pagination query string:
142
-
143
- ```
144
- ?page=2&per_page=12
145
- ```
146
-
147
- Your colletion will be build inside a JSON along with some metadata about it. The response structure is:
148
-
149
- ```
150
- { entries: [{Record1}, {Record2}, {Record3} ... {Record12}],
151
- total: 1234,
152
- total_pages: 102,
153
- last_page: false,
154
- previous_page: localhost:3000/my_records?page=1&per_page=12,
155
- next_page: localhost:3000/my_records?page=3&per_page=12,
156
- out_of_bounds: false,
157
- offset: 12 }
158
- ```
159
-
160
- ### Fieldset selecting
161
-
162
- Sometimes your data can grow large in some tables and you need to consumed only a limited set of data on a given frontend application. To avoid large requests and filtering a lot of unused data with JS you can restrict which fields you need on your API's reponse. This is done adding a `?select` parameter. Just pass the field names you desire splitted by `,`
163
- Let's say you are building a user list with their name, e-mails and phones, to get only those fields your URL query would look something like:
164
-
165
- ```
166
- ?select=name,email,phone
167
- ```
168
-
169
- This will change the response to return only the requested attributes. You need to observe that your business logic may require some fields for a valid response to be returned. **This method can be used both on index and show actions**
170
-
171
- ### Including relations or methods on response
172
-
173
- If there is any method or relation that you want to be inserted on the payload, you just need to pass them as a part of the URL query like this:
174
-
175
- ```
176
- ?include=pictures,suggestions
177
- ```
178
-
179
- This will insert the contents of `.pictures` and `.suggestions` on the payload, along with the records' data. This means you can populate the payload both with methods or relations contents. **This method can be used both on index and show actions**
180
-
181
- ### Grouping operations
182
-
183
- If you need to make grouping calculations, like:
184
-
185
- - Counting of all records, or by one **optional** field presence
186
- - Maximum value of one field
187
- - Minimum value of one field
188
- - Average value of one field
189
- - Value sum of one field
190
-
191
- Grouping is done by the combination of 3 parameters
192
-
193
- ```
194
- ?group[by]=a_field&group[calculate]=count&group[fields]=another_field
195
- ```
196
-
197
- Each of those attributes on the `?group` parameter represent an option of the query being made.
198
-
199
- - `group[by]` - Represents which field will be the key for the grouping behavior
200
- - `group[calculate]` - Which calculation will be sent in the response. Options are: `count`, `maximum`, `minimum`, `average`, `sum`
201
- - `group[field]` - Represents which field will be the base for the response calculation.
202
-
203
- # Contributing
204
-
205
- Bug reports and pull requests are welcome on GitHub at https://github.com/ErvalhouS/APIcasso. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant code of conduct](http://contributor-covenant.org/). To find good places to start contributing, try looking into our issue list and our Codeclimate profile, or if you want to participate actively on what the core team is working on checkout our todo list:
206
-
207
- ### TODO
208
-
209
- - Add support to other databases
210
- - Abstract a configurable CORS approach, maybe using middleware
211
- - Add gem options like: Token rotation, Alternative authentication methods
212
- - Refine and document auto-documentation feature
213
- - Rate limiting
214
- - Testing suite
215
- - Travis CI
216
-
217
- # Code of conduct
218
-
219
- Everyone interacting in the APIcasso project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ErvalhouS/APIcasso/blob/master/CODE_OF_CONDUCT.md).
220
-
221
- # License
222
-
223
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
1
+ <img src="https://raw.githubusercontent.com/ErvalhouS/APIcasso/master/APIcasso.png" width="300" /> [![Gem Version](https://badge.fury.io/rb/apicasso.svg)](https://badge.fury.io/rb/apicasso) [![Docs Coverage](https://inch-ci.org/github/autoforce/APIcasso.svg?branch=master)](https://inch-ci.org/github/autoforce/APIcasso.svg?branch=master) [![Maintainability](https://api.codeclimate.com/v1/badges/b58bbd6b9a0376f7cfc8/maintainability)](https://codeclimate.com/github/autoforce/APIcasso/maintainability) [![codecov](https://codecov.io/gh/autoforce/APIcasso/branch/master/graph/badge.svg)](https://codecov.io/gh/autoforce/APIcasso) [![Build Status](https://travis-ci.org/autoforce/APIcasso.svg?branch=master)](https://travis-ci.org/autoforce/APIcasso)
2
+
3
+ JSON API development can get boring and time consuming. If you think it through, every time you make one you use almost the same route structure, pointing to the same controller actions, with the same ordering, filtering and pagination features.
4
+
5
+ **APIcasso** is intended to be used as a full-fledged CRUD JSON API or as a base controller to speed-up development.
6
+ It is a route-based resource abstraction using API key scoping. This makes it possible to make CRUD-only applications just by creating functional Rails' models. It is a perfect candidate for legacy Rails projects that do not have an API. Access to your application's resources is managed by a `.scope` JSON object per API key. It uses that permission scope to restrict and extend access.
7
+
8
+ # Installation
9
+
10
+ Add this line to your application's `Gemfile`:
11
+
12
+ ```ruby
13
+ gem 'apicasso'
14
+ ```
15
+
16
+ And then execute this to generate the required migrations:
17
+
18
+ ```bash
19
+ $ bundle install && rails g apicasso:install
20
+ ```
21
+
22
+ # Requirements
23
+
24
+ - PostgreSQL with JSON columns support
25
+ - Ruby 2.3+
26
+
27
+ # Usage
28
+
29
+ **APIcasso** is meant to be used as an engine, which means you don't need to configure any route or controller to build a working CRUD API. Sometimes you also need some customized controller actions or even a specific logic to access some of your application's resources. In that case you will use `Apicasso::CrudController` class to easily build only your own logic around the API abstraction.
30
+
31
+ ## Mounting engine into `config/routes.rb`
32
+
33
+ After installing it, you can mount a full-fledged CRUD JSON API just by attaching into some route. Usually you will have it under a scoped route like `/api/v1` or a subdomain. You can do that by adding this into your `config/routes.rb`:
34
+
35
+ ```ruby
36
+ # To mount your APIcasso routes under the path scope `/api/v1`
37
+ mount Apicasso::Engine, at: "/api/v1"
38
+ # or, if you prefer subdomain scope isolation
39
+ constraints subdomain: 'apiv1' do
40
+ mount Apicasso::Engine, at: "/"
41
+ end
42
+ ```
43
+
44
+ Your API will reflect very similarly a `resources :resource` statement with the following routes:
45
+
46
+ ```ruby
47
+ get '/:resource/' # Index action, listing a `:resource` collection from your application
48
+ post '/:resource/' # Create action for one `:resource` from your application
49
+ get '/:resource/:id' # Show action for one `:resource` from your application
50
+ patch '/:resource/:id' # Update action for one `:resource` from your application
51
+ delete '/:resource/:id' # Destroy action for one `:resource` from your application
52
+ get '/:resource/:id/:nested/' # Index action, listing a collection of a `:nested` relation from one of your application's `:resource`
53
+ options '/:resource/' # A schema dump for the required `:resource`
54
+ options '/:resource/:id/:nested/' # A schema dump for the required `:nested` relation from one of your application's `:resource`
55
+ ```
56
+
57
+ This means all your application's models will be exposed as `:resource` and it's relations will be exposed as `:nested`. It will enable you to CRUD and get schema metadata from your records.
58
+
59
+ ## Extending base API actions
60
+
61
+ When your application needs some kind of custom interaction that is not covered by APIcasso's CRUD approach you can make your own actions using our base classes and objects to go straight into your logic. If you have built the APIcasso's engine into a route it is important that your custom action takes precedence over the gem's ones. To do that you need to declare your custom route before the engine on you `config/routes.rb`
62
+
63
+ ```ruby
64
+ match '/:resource/:id/a-custom-action' => 'custom#not_a_crud', via: :get
65
+ mount Apicasso::Engine, at: "/api/v1"
66
+ ```
67
+
68
+ And in your `app/controllers/custom_controller.rb` you would have something like:
69
+
70
+ ```ruby
71
+ class CustomController < Apicasso::CrudController
72
+ def not_a_crud
73
+ render json: @object.some_operation
74
+ end
75
+ end
76
+ ```
77
+
78
+ This way you enjoy all our object finder, authorization and authentication features, making your job more straight into your business logic.
79
+
80
+ ## Authentication
81
+
82
+ > But exposing my models to the internet is permissive as hell! Haven't you thought about security?
83
+
84
+ _Sure!_ The **APIcasso** suite is exposing your application using authentication through `Authorization: Token` [HTTP header authentication](http://tools.ietf.org/html/draft-hammer-http-token-auth-01). The API key objects are manageable through the `Apicasso::Key` model, which gets setup at install. When a new key is created a `.token` is generated using an [Universally Unique Identifier(RFC 4122)](https://tools.ietf.org/html/rfc4122). A authenticated request looks like this:
85
+
86
+ ```
87
+ curl -X GET \
88
+ https://apixample.com/v1/your_app_resource \
89
+ -H 'authorization: Token token=cda4e9f633c123ef9ddce5e6564292b3'
90
+ ```
91
+
92
+ Each `Apicasso::Key` object has a token attribute, which is used on this header to authorize access. For now, there is no plans for a login/JWT logic, you should implement this in your project's scope.
93
+
94
+ ## Authorization
95
+
96
+ Your Models are then exposed based on each `Apicasso::Key.scope` definition, which is a way to configure how much of your application each key can access. I.E.:
97
+
98
+ ```ruby
99
+ Apicasso::Key.create(scope:
100
+ { manage:
101
+ { order: true, user: { account_id: 1 } },
102
+ read:
103
+ { account: { manager_id: 1 } }
104
+ })
105
+ ```
106
+
107
+ > The key from this example will have full access to all orders and to users with `account_id == 1`. It will have also read-only access to accounts with `id == 1`.
108
+
109
+ A scope configured like this translates directly into which kind of access each key has on all of your application's models. This kind of authorization is why one of the dependencies for this gem is [CanCanCan](https://github.com/CanCanCommunity/cancancan), which abstracts the scope field into your API access control.
110
+
111
+ You can have two kind of access control:
112
+
113
+ - `true` - This will mean the key will have the declared clearance on **ALL** of this model's records
114
+ - `Hash` - This will build a condition to what records this key have access to. A scope as `{ read: [{ account: { manager_id: 1 } }] }` will have read access into accounts with `manager_id == 1`
115
+
116
+ This saves you the trouble of having to setup every controller for each model. And even if your application really needs it, just make your controllers inherit from `Apicasso::CrudController` extending it and enabling the use of `@object` and `@resource` variables to access what is being resquested.
117
+
118
+ ## Features on index actions
119
+
120
+ The index actions present in the gem are already equipped with pagination, ordering, grouping, fieldset selection and filtering. This will save you a lot of trouble, adding some best-practices conventions into your application's API.
121
+
122
+ ### Sort
123
+
124
+ You can sort a collection query by using a URL parameter with field names preffixed with `+` or `-` to configure custom ordering per request.
125
+
126
+ To order a collection with ascending `updated_at` and descending `name` you can add the `sort` parameter with those fields as options, indicating which kind of ordination you want to give to each one:
127
+
128
+ ```
129
+ ?sort=+updated_at,-name
130
+ ```
131
+
132
+ ### Filtering/Search
133
+
134
+ APIcasso has [ransack's search matchers](https://github.com/activerecord-hackery/ransack#search-matchers) on it's index actions. This means you can dynamically build search queries with any of your resource's fields, this will be done by using a `?q` parameter which groups all your filtering options on your requests. If you wanted to search all your records and return only the ones with `full_name` starting with `Picasso` your query would look something like this:
135
+
136
+ ```
137
+ ?q[full_name_start]=Picasso
138
+ ```
139
+
140
+ To build complex search queries you can chain many parameter options or check [ransack's wiki](https://github.com/activerecord-hackery/ransack/wiki/) on how to adapt this feature into your project's needs.
141
+
142
+ ### Pagination
143
+
144
+ Automatic pagination is done in index actions, with the adittion of some metadata to help on the data consumption. You can pass page and per page parameters to build pagination options into your needs. And on requests that you need unpaginated collections, just pass a lower than zero `per_page`. Example of a pagination query string:
145
+
146
+ ```
147
+ ?page=2&per_page=12
148
+ ```
149
+
150
+ Your colletion will be build inside a JSON along with some metadata about it. The response structure is:
151
+
152
+ ```
153
+ { entries: [{Record1}, {Record2}, {Record3} ... {Record12}],
154
+ total: 1234,
155
+ total_pages: 102,
156
+ last_page: false,
157
+ previous_page: localhost:3000/my_records?page=1&per_page=12,
158
+ next_page: localhost:3000/my_records?page=3&per_page=12,
159
+ out_of_bounds: false,
160
+ offset: 12 }
161
+ ```
162
+
163
+ ### Fieldset selecting
164
+
165
+ Sometimes your data can grow large in some tables and you need to consumed only a limited set of data on a given frontend application. To avoid large requests and filtering a lot of unused data with JS you can restrict which fields you need on your API's reponse. This is done adding a `?select` parameter. Just pass the field names you desire splitted by `,`
166
+ Let's say you are building a user list with their name, e-mails and phones, to get only those fields your URL query would look something like:
167
+
168
+ ```
169
+ ?select=name,email,phone
170
+ ```
171
+
172
+ This will change the response to return only the requested attributes. You need to observe that your business logic may require some fields for a valid response to be returned. **This method can be used both on index and show actions**
173
+
174
+ ### Including relations or methods on response
175
+
176
+ If there is any method or relation that you want to be inserted on the payload, you just need to pass them as a part of the URL query like this:
177
+
178
+ ```
179
+ ?include=pictures,suggestions
180
+ ```
181
+
182
+ This will insert the contents of `.pictures` and `.suggestions` on the payload, along with the records' data. This means you can populate the payload both with methods or relations contents. **This method can be used both on index and show actions**
183
+
184
+ ### Grouping operations
185
+
186
+ If you need to make grouping calculations, like:
187
+
188
+ - Counting of all records, or by one **optional** field presence
189
+ - Maximum value of one field
190
+ - Minimum value of one field
191
+ - Average value of one field
192
+ - Value sum of one field
193
+
194
+ Grouping is done by the combination of 3 parameters
195
+
196
+ ```
197
+ ?group[by]=a_field&group[calculate]=count&group[fields]=another_field
198
+ ```
199
+
200
+ Each of those attributes on the `?group` parameter represent an option of the query being made.
201
+
202
+ - `group[by]` - Represents which field will be the key for the grouping behavior
203
+ - `group[calculate]` - Which calculation will be sent in the response. Options are: `count`, `maximum`, `minimum`, `average`, `sum`
204
+ - `group[field]` - Represents which field will be the base for the response calculation.
205
+
206
+ # Contributing
207
+
208
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ErvalhouS/APIcasso. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant code of conduct](http://contributor-covenant.org/). To find good places to start contributing, try looking into our issue list and our Codeclimate profile, or if you want to participate actively on what the core team is working on checkout our todo list:
209
+
210
+ ### TODO
211
+
212
+ - Add support to other databases
213
+ - Abstract a configurable CORS approach, maybe using middleware
214
+ - Add gem options like: Token rotation, Alternative authentication methods
215
+ - Refine and document auto-documentation feature
216
+ - Rate limiting
217
+ - Testing suite
218
+ - Travis CI
219
+
220
+ # Code of conduct
221
+
222
+ Everyone interacting in the APIcasso project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ErvalhouS/APIcasso/blob/master/CODE_OF_CONDUCT.md).
223
+
224
+ # License
225
+
226
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,23 +1,23 @@
1
- #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
- require 'bundler/gem_tasks'
8
- require 'rspec/core/rake_task'
9
-
10
- APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
11
- load 'rails/tasks/engine.rake'
12
-
13
- Bundler::GemHelper.install_tasks
14
-
15
- Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
16
-
17
- require 'rspec/core'
18
- require 'rspec/core/rake_task'
19
-
20
- desc 'Run all specs in spec directory (excluding plugin specs)'
21
- RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
22
-
23
- task default: :spec
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ require 'bundler/gem_tasks'
8
+ require 'rspec/core/rake_task'
9
+
10
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
11
+ load 'rails/tasks/engine.rake'
12
+
13
+ Bundler::GemHelper.install_tasks
14
+
15
+ Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
16
+
17
+ require 'rspec/core'
18
+ require 'rspec/core/rake_task'
19
+
20
+ desc 'Run all specs in spec directory (excluding plugin specs)'
21
+ RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
22
+
23
+ task default: :spec