model_driven_api 2.3.6 → 2.3.11
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f318cd8434ed86ff9045ec0a2849774d2d4232f9b057ea70c2313f2255011ff6
|
4
|
+
data.tar.gz: b587c4fee867ea15389db03d191c899061856fc8a53beea17bf7b88f0aa86cf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d92b432a32ee4a23c2209f66ab40eb6d2f56bb3fc9b7229da63eba8a105aacdfcfea36b21cb2739f879077e9f736e1b0ba3e5c4d0602b070cc388aaec684cefa
|
7
|
+
data.tar.gz: 330b5cbc65fed482fc7af84368967ae3987047d6235f68b5f8fa1b8757c626dbfcde0f6bdde13d3f644666850f24be6cd9a793ffe6ea528ed78b35d9dc8cb933
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# Model Driven Api
|
2
2
|
|
3
|
-
##
|
3
|
+
## Goals
|
4
4
|
|
5
|
-
To have a comprehensive and meaningful Model driven API right out of the box by just creating migrations in your rails app or engine. With all the CRUD operations in place out of the box and easily expandable with custom actions if needed.
|
5
|
+
* To have a comprehensive and meaningful Model driven API right out of the box by just creating migrations in your rails app or engine. With all the CRUD operations in place out of the box and easily expandable with custom actions if needed.
|
6
|
+
* To have a plain REST implementation which adapts the returned JSON to the specific needs of the client, **without the need to change backend code**, this may overcome the biggest disadvantage of REST vs GraphQL = client driver presentation.
|
6
7
|
|
7
8
|
## TL;DR 5-10 minutes adoption
|
8
9
|
|
@@ -27,6 +28,55 @@ I've always been interested in effortless, no-fuss, conventions' based developme
|
|
27
28
|
|
28
29
|
Doing this means also narrowing a bit the scope of the tools, taking decisions, at least for the first implementations and versions of this engine, so, this works well if the data is relational, this is a prerequisite (postgres, mysql, mssql, etc.).
|
29
30
|
|
31
|
+
## REST Enhanced
|
32
|
+
|
33
|
+
Thanks to the inclusion of [Ransack](https://github.com/activerecord-hackery/ransack/wiki) and [ActiveModel::Serializer](https://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html), by just adding the querystring keys **q** and **a**, you can create complex queries (q) to obtain just the records you need, which present in the returnd JSON just the attributes (a) needed.
|
34
|
+
By combining the two keys, you can obtain just the data you want.
|
35
|
+
|
36
|
+
The *json_attrs* or *a* query string passed accepts these keys (Please see [ActiveModel::Serializer](https://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html) for reference):
|
37
|
+
- only: list [] of model fields to be shown in JSON serialization
|
38
|
+
- except: exclude these fields from the JSON serialization, this is a list []
|
39
|
+
- methods: include the result of some methods defined in the model, this is a list []
|
40
|
+
- include: include associated models, it's an object {} which also accepts the keys described in this document (only, except, methods, include)
|
41
|
+
|
42
|
+
### Example
|
43
|
+
|
44
|
+
```
|
45
|
+
{{ base_url }}/{{ controller }}?a[only][]=locked&a[only][]=username&a[methods][]=jwe_data
|
46
|
+
```
|
47
|
+
|
48
|
+
Is translated to:
|
49
|
+
|
50
|
+
```
|
51
|
+
{a: {only: ["locked", "username"], methods: ["jwe_data"]}}
|
52
|
+
```
|
53
|
+
|
54
|
+
Which tells the API controller just to return this optimized serialization:
|
55
|
+
|
56
|
+
```
|
57
|
+
[
|
58
|
+
{
|
59
|
+
"username": "Administrator",
|
60
|
+
"locked": false,
|
61
|
+
"jwe_data": "eyJhbGciOiJkaXIiLCJlbmMiOiJSMTI4R0NNIn0..yz0tnC6y3BzgoOsO.BjHb9CRIb0vrv7nnEx54Ac8-cATPJ9sTlQSSxRbTmtcPHc5KhvtyE_hyBRnIcK92bzUBRwdy6ASB2XJVy1VfWxAmO8E.4tOzJlfuXi-shaRhDSkOyg"
|
62
|
+
}
|
63
|
+
]
|
64
|
+
```
|
65
|
+
|
66
|
+
By combinig with Ransack's **q** query string key (please read [Ransack](https://github.com/activerecord-hackery/ransack/wiki) documentation to discover all the possible and complex searches you can make), you can obtain right what you want:
|
67
|
+
|
68
|
+
```
|
69
|
+
{{ base_url }}/{{ controller }}?a[only][]=locked&a[only][]=username&a[methods][]=jwe_data&q[email_cont][]=adm
|
70
|
+
```
|
71
|
+
|
72
|
+
Which translates to:
|
73
|
+
|
74
|
+
```
|
75
|
+
{a: {only: ["locked", "username"], methods: ["jwe_data"]}, q: { email_cont: ["adm"]}}
|
76
|
+
```
|
77
|
+
|
78
|
+
For bigger searches, which may over crowd the querystring length, you can always use the default [Search](#Search) POST endpoint.
|
79
|
+
|
30
80
|
## v2?
|
31
81
|
|
32
82
|
Yes, this is the second version of such an effort and you can note it from the api calls, which are all under the ```/api/v2``` namespace the [/api/v1](https://github.com/gabrieletassoni/thecore_api) one, was were it all started, many ideas are ported from there, such as the generation of the automatic model based crud actions, as well as custom actions definitions and all the things that make also this gem useful for my daily job were already in place, but it was too coupled with [thecore](https://github.com/gabrieletassoni/thecore)'s [rails_admin](https://github.com/sferik/rails_admin) UI, making it impossible to create a complete UI-less, API only application, out of the box and directly based of the DB schema, with all the bells and whistles I needed (mainly self adapting, data and schema driven API functionalities).
|
@@ -20,7 +20,10 @@ class Api::V2::ApplicationController < ActionController::API
|
|
20
20
|
return render json: result, status: 200 if status == true
|
21
21
|
|
22
22
|
# Normal Index Action with Ransack querying
|
23
|
-
|
23
|
+
# Keeping this automation can be too dangerous and lead to unpredicted results
|
24
|
+
# TODO: Remove it
|
25
|
+
# @q = (@model.column_names.include?("user_id") ? @model.where(user_id: current_user.id) : @model).ransack(@query.presence|| params[:q])
|
26
|
+
@q = @model.ransack(@query.presence|| params[:q])
|
24
27
|
@records_all = @q.result # (distinct: true) Removing, but I'm not sure, with it I cannot sort in postgres for associated records (throws an exception on misuse of sort with distinct)
|
25
28
|
page = (@page.presence || params[:page])
|
26
29
|
per = (@per.presence || params[:per])
|
@@ -66,7 +69,9 @@ class Api::V2::ApplicationController < ActionController::API
|
|
66
69
|
return render json: result, status: 200 if status == true
|
67
70
|
|
68
71
|
# Normal Create Action
|
69
|
-
|
72
|
+
# Keeping this automation can be too dangerous and lead to unpredicted results
|
73
|
+
# TODO: Remove it
|
74
|
+
# @record.user_id = current_user.id if @model.column_names.include? "user_id"
|
70
75
|
@record.save!
|
71
76
|
render json: @record.to_json(json_attrs), status: 201
|
72
77
|
end
|
@@ -108,7 +113,8 @@ class Api::V2::ApplicationController < ActionController::API
|
|
108
113
|
resource = "custom_action_#{params[:do]}"
|
109
114
|
raise NoMethodError unless @model.respond_to?(resource)
|
110
115
|
# return true, MultiJson.dump(params[:id].blank? ? @model.send(resource, params) : @model.send(resource, params[:id].to_i, params))
|
111
|
-
|
116
|
+
puts json_attrs
|
117
|
+
return true, @model.send(resource, params).to_json(json_attrs)
|
112
118
|
end
|
113
119
|
# if it's here there is no custom action in the request querystring
|
114
120
|
return false
|
@@ -143,12 +149,19 @@ class Api::V2::ApplicationController < ActionController::API
|
|
143
149
|
|
144
150
|
def find_record
|
145
151
|
record_id ||= (params[:path].split("/").second.to_i rescue nil)
|
146
|
-
|
152
|
+
# Keeping this automation can be too dangerous and lead to unpredicted results
|
153
|
+
# TODO: Remove it
|
154
|
+
# @record = @model.column_names.include?("user_id") ? @model.where(id: (record_id.presence || @record_id.presence || params[:id]), user_id: current_user.id).first : @model.find((@record_id.presence || params[:id]))
|
155
|
+
@record = @model.find((@record_id.presence || params[:id]))
|
147
156
|
return not_found! if @record.blank?
|
148
157
|
end
|
149
158
|
|
150
159
|
def json_attrs
|
151
|
-
|
160
|
+
# In order of importance: if you send the configuration via querystring you are ok
|
161
|
+
# has precedence over if you have setup the json_attrs in the model concern
|
162
|
+
from_params = params[:a].deep_symbolize_keys unless params[:a].blank?
|
163
|
+
from_params = params[:json_attrs].deep_symbolize_keys unless params[:json_attrs].blank?
|
164
|
+
from_params.presence || @json_attrs.presence || @model.json_attrs.presence || {} rescue {}
|
152
165
|
end
|
153
166
|
|
154
167
|
def extract_model
|
@@ -6,7 +6,7 @@ class Api::V2::InfoController < Api::V2::ApplicationController
|
|
6
6
|
|
7
7
|
# api :GET, '/api/v2/info/version', "Just prints the APPVERSION."
|
8
8
|
def version
|
9
|
-
render json: { version:
|
9
|
+
render json: { version: "TODO: Find a Way to Dynamically Obtain It" }.to_json, status: 200
|
10
10
|
end
|
11
11
|
|
12
12
|
# api :GET, '/api/v2/info/roles'
|
@@ -10,6 +10,7 @@ module ApiExceptionManagement
|
|
10
10
|
rescue_from ActiveModel::ForbiddenAttributesError, with: :fivehundred!
|
11
11
|
rescue_from ActiveRecord::RecordInvalid, with: :invalid!
|
12
12
|
rescue_from ActiveRecord::RecordNotFound, with: :not_found!
|
13
|
+
rescue_from ActiveRecord::RecordNotUnique, with: :invalid!
|
13
14
|
end
|
14
15
|
|
15
16
|
def unauthenticated! exception = AuthenticateUser::AccessDenied.new
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model_driven_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gabriele Tassoni
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thecore_backend_commons
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- config/initializers/after_initialize_for_model_driven_api.rb
|
143
143
|
- config/initializers/cors_api_thecore.rb
|
144
144
|
- config/initializers/knock.rb
|
145
|
+
- config/initializers/time_with_zone.rb
|
145
146
|
- config/initializers/wrap_parameters.rb
|
146
147
|
- config/routes.rb
|
147
148
|
- lib/concerns/api_exception_management.rb
|