model_driven_api 3.1.9 → 3.1.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: 94b18a1b177632591c520596c5b8443da17b84937c934b450550512355d4690d
4
- data.tar.gz: 8992f753df4957e584a303989130f48ef63346f9adff290f72140bc2f7df14f7
3
+ metadata.gz: 0afb3dc1dca5b7277c7ea2bfd601669765d5227fe68ede17fa6fbfc3de19d36f
4
+ data.tar.gz: 02c3ece69e6237b42f8f04de6660469d528c81a84cf392a34a743360b765d832
5
5
  SHA512:
6
- metadata.gz: be09d8af6479897b60e760e1d8a1096804acca2a881a9dba302af39a701eeeba3e801ca09bd25caadcdc3a4ae20d8ea0280e9e70458331ea2a53d6a7bbba55b0
7
- data.tar.gz: a49c63942e572826abe3e6176bca618589993da59957d012a34db8b49acd4550102b0fb8987a8a602faf20be56363ace53c53fe1496feb97316cd7796edf736d
6
+ metadata.gz: 92c3d537101cb23123ce34564eaac4fe1d767770628dddcd1cc94487253bb82c880e07721a78c2be3dc571c370020b12e13ab30e9981d035c7766634dccdeb7b
7
+ data.tar.gz: 69385bf1c20fe26e8168be63da529edb847002984084e133e431aef6b07815bb88edf1f42ed43d65dc0ef5194a28ede011c29f05aca3de0176dd11a119da3a8a
@@ -66,7 +66,6 @@ class Api::V2::ApplicationController < ActionController::API
66
66
 
67
67
  def create
68
68
  # Normal Create Action
69
- @record = @model.new(@body)
70
69
  authorize! :create, @record
71
70
  # Custom Action
72
71
  status, result, status_number = check_for_custom_action
@@ -74,6 +73,7 @@ class Api::V2::ApplicationController < ActionController::API
74
73
  # Keeping this automation can be too dangerous and lead to unpredicted results
75
74
  # TODO: Remove it
76
75
  # @record.user_id = current_user.id if @model.column_names.include? "user_id"
76
+ @record = @model.new(@body)
77
77
  @record.save!
78
78
  render json: @record.to_json(json_attrs), status: 201
79
79
  end
@@ -158,11 +158,13 @@ class Api::V2::ApplicationController < ActionController::API
158
158
  # The endpoint can be expressed in two ways:
159
159
  # 1. As a method in the model, with suffix custom_action_<custom_action>
160
160
  # 2. As a module instance method in the model, like Track::Endpoints.inventory
161
- if defined?("Endpoints::#{@model}.#{custom_action}")
162
- # Custom endpoint exists and can be called in the sub-modules form
163
- body, status = "Endpoints::#{@model}".constantize.send(custom_action, params)
164
- elsif @model.respond_to?("custom_action_#{custom_action}")
161
+ # Example:
162
+ # Endpoints::TestApi.new(:test, {request_verb: "POST", is_connected: "Uhhhh"}).result
163
+ if @model.respond_to?("custom_action_#{custom_action}")
165
164
  body, status = @model.send("custom_action_#{custom_action}", params)
165
+ elsif ("Endpoints::#{@model}".constantize rescue false) && "Endpoints::#{@model}".constantize.instance_methods.include?(custom_action.to_sym)
166
+ # Custom endpoint exists and can be called in the sub-modules form
167
+ body, status = "Endpoints::#{@model}".constantize.new(custom_action, params).result
166
168
  else
167
169
  # Custom endpoint does not exist or cannot be called
168
170
  raise NoMethodError
@@ -0,0 +1,56 @@
1
+ class Endpoints::TestApi < NonCrudEndpoints
2
+ def test(params)
3
+ # Define an explain var to be used to validate and document the action behavior when using ?explain=true in query string
4
+ explain = {
5
+ verbs: ["GET", "POST"],
6
+ body: {
7
+ messages: {
8
+ type: :array,
9
+ optional: true,
10
+ items: {
11
+ type: :string,
12
+ optional: false
13
+ }
14
+ },
15
+ is_connected: {
16
+ type: :boolean,
17
+ optional: false
18
+ },
19
+ user: {
20
+ type: :object,
21
+ optional: true,
22
+ properties: {
23
+ name: {
24
+ type: :string,
25
+ optional: false
26
+ },
27
+ age: {
28
+ type: :integer,
29
+ optional: true
30
+ }
31
+ }
32
+ }
33
+ },
34
+ query: {
35
+ explain: {
36
+ type: :boolean,
37
+ optional: true
38
+ }
39
+ },
40
+ responses: {
41
+ 200 => {
42
+ message: :string,
43
+ params: {},
44
+ },
45
+ 501 => {
46
+ error: :string,
47
+ },
48
+ },
49
+ }
50
+ return explain, 200 if params[:explain].to_s == "true" && !explain.blank?
51
+
52
+
53
+ return { message: "Hello World From Test API Custom Action called test", params: params }, 200
54
+ end
55
+ end
56
+ # end
@@ -1,6 +1,2 @@
1
1
  class TestApi
2
- # Initialize the class with the request params
3
- def initialize params
4
- @params = params
5
- end
6
2
  end
data/config/routes.rb CHANGED
@@ -30,17 +30,17 @@ Rails.application.routes.draw do
30
30
  patch ":ctrl/custom_action/:action_name/:id", to: 'application#update'
31
31
  delete ":ctrl/custom_action/:action_name/:id", to: 'application#destroy'
32
32
  # Catchall routes
33
- # # # CRUD Show
34
- # get '*path/:id', to: 'application#show'
35
- # # # CRUD Index
36
- # get '*path', to: 'application#index'
37
- # # # CRUD Create
38
- # post '*path', to: 'application#create'
39
- # # CRUD Update
33
+ # # CRUD Show
34
+ get '*path/:id', to: 'application#show'
35
+ # # CRUD Index
36
+ get '*path', to: 'application#index'
37
+ # # CRUD Create
38
+ post '*path', to: 'application#create'
39
+ # CRUD Update
40
40
  put '*path/:id/multi', to: 'application#update_multi'
41
41
  patch '*path/:id/multi', to: 'application#update_multi'
42
- # put '*path/:id', to: 'application#update'
43
- # patch '*path/:id', to: 'application#patch'
42
+ put '*path/:id', to: 'application#update'
43
+ patch '*path/:id', to: 'application#patch'
44
44
 
45
45
  # # CRUD Delete
46
46
  delete '*path/:id/multi', to: 'application#destroy_multi'
@@ -11,6 +11,7 @@ module ApiExceptionManagement
11
11
  rescue_from ActiveRecord::RecordInvalid, with: :invalid!
12
12
  rescue_from ActiveRecord::RecordNotFound, with: :not_found!
13
13
  rescue_from ActiveRecord::RecordNotUnique, with: :invalid!
14
+ rescue_from EndpointValidationError, with: :api_error
14
15
  end
15
16
 
16
17
  def unauthenticated! exception = AuthenticateUser::AccessDenied.new
@@ -34,7 +35,7 @@ module ApiExceptionManagement
34
35
  return api_error status: 500, errors: exception.message
35
36
  end
36
37
 
37
- def api_error(status: 500, errors: [])
38
+ def api_error(status: 501, errors: [])
38
39
  # puts errors.full_messages if !Rails.env.production? && errors.respond_to?(:full_messages)
39
40
  head status && return if errors.blank?
40
41
 
@@ -0,0 +1,2 @@
1
+ class EndpointValidationError < StandardError
2
+ end
@@ -1,3 +1,3 @@
1
1
  module ModelDrivenApi
2
- VERSION = "3.1.9".freeze
2
+ VERSION = "3.1.10".freeze
3
3
  end
@@ -1,3 +1,5 @@
1
+ require 'endpoint_validation_error'
2
+ require 'non_crud_endpoints'
1
3
  require 'thecore_backend_commons'
2
4
  require 'rack/cors'
3
5
  require 'ransack'
@@ -0,0 +1,54 @@
1
+ class NonCrudEndpoints
2
+ attr_accessor :result
3
+ # Add a validation method which will be inherited by all the instances, and automatically run before any method call
4
+ def initialize(m, params)
5
+ # Check if self hase the m method, if not, raise a NoMethodError
6
+ raise NoMethodError, "The method #{m} does not exist in #{self.class}" unless self.respond_to? m
7
+ definition = self.send(m, { explain: true }) rescue []
8
+ validate_request(definition.first.presence || {}, params)
9
+ @result = self.send(m, params)
10
+ end
11
+
12
+ def validate_request(definition, params)
13
+ # If there is no definition, return
14
+ return if definition.blank?
15
+ # puts "Called Class is: #{self.class}"
16
+ # puts "Which is son of: #{self.class.superclass}"
17
+ body_mandatory_keys = definition[:body].select { |k, v| v[:optional] == false }.keys
18
+ query_mandatory_keys = definition[:query].select { |k, v| v[:optional] == false }.keys
19
+ # Raise a ValidationError if the request does not match the definition
20
+ raise EndpointValidationError, "The verb \"#{params[:request_verb].presence || "No Verb Provided"}\" is not present in #{definition[:verbs].join(", ")}." if definition[:verbs].exclude? params[:request_verb]
21
+ # Raise an exception if the verb is put or post and the body keys in definition are not all present as params keys, both params and definition[:body] can have nested objects
22
+ raise EndpointValidationError, "The request body does not match the definition: in #{params[:request_verb]} requests all of the params must be present in definition. The body definition is #{definition[:body]}." if params[:request_verb] != "GET" && (body_mandatory_keys & params.keys) != body_mandatory_keys
23
+ # Raise an exception if the verb is put or post and the body keys in definition are not all present as params keys, both params and definition[:body] can have nested objects
24
+ raise EndpointValidationError, "The request query does not match the definition. The query definition is: #{definition[:query]}." if (query_mandatory_keys & params.keys) != query_mandatory_keys
25
+ # Rais if the type of the param is not the same as the definition
26
+ definition[:body].each do |k, v|
27
+ next if params[k].nil?
28
+ computed_type = get_type(params[k])
29
+ raise EndpointValidationError, "The type of the param #{k} is not the same as the definition. The definition is #{v[:type]} and the param is #{computed_type}." if v[:type] != computed_type
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def get_type(type)
36
+ case type
37
+ when String
38
+ :string
39
+ when Integer
40
+ :integer
41
+ when Float
42
+ :number
43
+ when TrueClass, FalseClass
44
+ :boolean
45
+ when Array
46
+ :array
47
+ when Hash
48
+ :object
49
+ else
50
+ :undefined
51
+ end
52
+ end
53
+ end
54
+
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: 3.1.9
4
+ version: 3.1.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: 2024-03-06 00:00:00.000000000 Z
11
+ date: 2024-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thecore_backend_commons
@@ -125,7 +125,7 @@ files:
125
125
  - app/controllers/api/v2/authentication_controller.rb
126
126
  - app/controllers/api/v2/info_controller.rb
127
127
  - app/controllers/api/v2/users_controller.rb
128
- - app/models/concerns/endpoints/test_api.rb
128
+ - app/models/endpoints/test_api.rb
129
129
  - app/models/test_api.rb
130
130
  - app/models/used_token.rb
131
131
  - config/initializers/after_initialize_for_model_driven_api.rb
@@ -140,10 +140,12 @@ files:
140
140
  - lib/concerns/model_driven_api_application_record.rb
141
141
  - lib/concerns/model_driven_api_role.rb
142
142
  - lib/concerns/model_driven_api_user.rb
143
+ - lib/endpoint_validation_error.rb
143
144
  - lib/json_web_token.rb
144
145
  - lib/model_driven_api.rb
145
146
  - lib/model_driven_api/engine.rb
146
147
  - lib/model_driven_api/version.rb
148
+ - lib/non_crud_endpoints.rb
147
149
  - lib/tasks/model_driven_api_tasks.rake
148
150
  homepage: https://github.com/gabrieletassoni/model_driven_api
149
151
  licenses:
@@ -1,23 +0,0 @@
1
- module Endpoints::TestApi
2
- def self.test params
3
- # Define an explain var to be used to validate and document the action behavior when using ?explain=true in query string
4
- explain = {
5
- verbs: ["GET"],
6
- body: {},
7
- query: {},
8
- responses: {
9
- 200 => {
10
- message: :string,
11
- params: {}
12
- },
13
- 501 => {
14
- error: :string
15
- }
16
- }
17
- }
18
-
19
- return explain, 200 if params[:explain] == "true"
20
- return { error: "This method responds only to #{explain[:verbs].join(", ")} requests" }, 501 if explain[:verbs].exclude? params[:request_verb]
21
- return { message: "Hello World From Test API Custom Action called test", params: params }, 200
22
- end
23
- end