model_driven_api 2.3.9 → 2.3.10

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: 1da45cd3ee59fe0a531f304af8a0333559584977238737395b78864a1020b2c2
4
- data.tar.gz: 49a829a12437ab3f901cad50689ef4d6de74824db86f42e5be5b050d897f9229
3
+ metadata.gz: 190f87343976c6c393f9b2c80163ddc403b2575fd2c8fcceb125ef1996e7532a
4
+ data.tar.gz: e393facfcd2b11ac2af44df2f5602074e2da1ee48974dbb2fdec6d4f346c837e
5
5
  SHA512:
6
- metadata.gz: 24bca1df42a775c4ea9d74d75ec6ac02de6e68e4e4693d433c03c2a1016535db81c9a2e37c419a4f51552f62c928306383db999a20448bf89aeac012449ecf52
7
- data.tar.gz: 8a345a1bc8d20e846b98d653bec7b8a6da86136cf88d5b38fa278476f10a5fb2785d31f8fe73bf03061b209d95f2fc2c27f426bf73c6cad93682f62507165abc
6
+ metadata.gz: b4f9083c41e709a64d99278f84594d28ac94175983678c01b2b08124facf2ccf3264808034a1c30eac3d2801a763807ffc480bbc4ab17afe929216b3ce096ece
7
+ data.tar.gz: 25e8013e5421b51b5fdce2d444fabdb5f66bc9e4805df7c2761646b43a0058dabf70ed7e11d2e36494740c0d5966ea300a4351a4f16754837caf0f23826a7b7e
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
1
  # Model Driven Api
2
2
 
3
- ## Goal
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
- @q = (@model.column_names.include?("user_id") ? @model.where(user_id: current_user.id) : @model).ransack(@query.presence|| params[:q])
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
- @record.user_id = current_user.id if @model.column_names.include? "user_id"
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
@@ -143,7 +148,10 @@ class Api::V2::ApplicationController < ActionController::API
143
148
 
144
149
  def find_record
145
150
  record_id ||= (params[:path].split("/").second.to_i rescue nil)
146
- @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]))
151
+ # Keeping this automation can be too dangerous and lead to unpredicted results
152
+ # TODO: Remove it
153
+ # @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]))
154
+ @record = @model.find((@record_id.presence || params[:id]))
147
155
  return not_found! if @record.blank?
148
156
  end
149
157
 
@@ -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.9
4
+ version: 2.3.10
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-03-24 00:00:00.000000000 Z
11
+ date: 2021-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thecore_backend_commons