model-api 0.8.10 → 0.8.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -13
- data/lib/model-api/base_controller.rb +3 -0
- data/lib/model-api/utils.rb +47 -0
- data/model-api.gemspec +1 -1
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f14172aa6fcaa7f2c314d673e4295338493588b
|
4
|
+
data.tar.gz: 43e8a3a180fb05ca4d527b953e78e091ecdc75fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50b16368bf036477dbf671d3b0e528e6533ca358a35ae917f4d8ff2408c61470fa161c3c1399850bba0ba0b5bd797c33bd80c81ebc806ece1fa5303971a36020
|
7
|
+
data.tar.gz: 7566d5be7fc86688cf8e09bfa58bab47b644b81e2c87f9859e05edfbd08c9dee37246f2294dae8300f411a9b1751624cd908a1a5a3fb74b113b5b9664e6f66bb
|
data/README.md
CHANGED
@@ -9,32 +9,35 @@ Developing REST API's in a conventional manner involves many challenges. Betwee
|
|
9
9
|
|
10
10
|
With model-api, you can:
|
11
11
|
* Consolidate your payload and response metadata for a given resource in the ActiveRecord model.
|
12
|
+
* Reduce the lines of code required to implement your Rails-based Rest API dramatically.
|
13
|
+
* Generate OpenAPI documentation guaranteed to be in sync with what your API actually supports.
|
12
14
|
* Set up easily-configurable filtering, pagination, sorting, and HATEOAS link generation.
|
13
15
|
* Render, link, create, search upon, and sort upon your resources' associated objects with ease.
|
14
|
-
*
|
15
|
-
|
16
|
-
*
|
17
|
-
sync with what your API actually supports.
|
18
|
-
* Reduce the lines of code required to implement your Rails-based Rest API dramatically.
|
16
|
+
* Leverage ActiveRecord validation rules in your application's models to validate API calls.
|
17
|
+
* Effortlessly support JSON and XML input / output formats together in the same API.
|
18
|
+
* Use Java-style camel-case for API content while utilizing Ruby underscore convention internally.
|
19
19
|
|
20
20
|
## Guides
|
21
21
|
This README file is intended to provide a brief introduction. For more detailed information,
|
22
22
|
the following guides are available:
|
23
|
-
* [Guide to `
|
24
|
-
* [Guide to `
|
25
|
-
* [Managing data access in `model-api`](doc/
|
23
|
+
* [Guide to `api_attributes` metadata](doc/api_attributes.md)
|
24
|
+
* [Guide to `api_model` metadata](doc/api_model.md)
|
25
|
+
* [Managing data access in `model-api`](doc/managing_data_access.md)
|
26
|
+
|
27
|
+
General information on the API (including enumerated constants, etc.) can be found here:
|
28
|
+
* [General gem usage information](doc/general_info.md)
|
26
29
|
|
27
30
|
## Installation
|
28
31
|
|
29
32
|
Put this in your Gemfile:
|
30
33
|
|
31
34
|
``` ruby
|
32
|
-
gem '
|
35
|
+
gem 'model-api'
|
33
36
|
```
|
34
37
|
|
35
38
|
## Configuration
|
36
39
|
|
37
|
-
The
|
40
|
+
The model-api gem doesn't require configuration. However, if you plan to generate OpenAPI
|
38
41
|
documentation, add an `open_api.rb` file to `config/initializers` and configure as follows:
|
39
42
|
|
40
43
|
``` ruby
|
@@ -78,9 +81,14 @@ class Book < ActiveRecord::Base
|
|
78
81
|
validates :name, presence: true, uniqueness: true, length: { maximum: 50 }
|
79
82
|
validates :description, length: { maximum: 250 }
|
80
83
|
validates :isbn, presence: true, uniqueness: true, length: { maximum: 13 }
|
81
|
-
|
84
|
+
|
85
|
+
# Define model-level rules and metadata associated with the REST API.
|
86
|
+
api_model(
|
87
|
+
base_query: ->(opts) { opts[:admin] ? Book.where(public: true) : Book.all }
|
88
|
+
)
|
89
|
+
|
82
90
|
# Define the attributes exposed via the REST API.
|
83
|
-
api_attributes
|
91
|
+
api_attributes(
|
84
92
|
id: { filter: true, sort: true },
|
85
93
|
name: { filter: true, sort: true },
|
86
94
|
description: {},
|
@@ -90,10 +98,14 @@ class Book < ActiveRecord::Base
|
|
90
98
|
},
|
91
99
|
created_at: { read_only: true, filter: true },
|
92
100
|
updated_at: { read_only: true, filter: true }
|
101
|
+
)
|
93
102
|
|
94
103
|
end
|
95
104
|
```
|
96
|
-
An explanation of the options used in the `
|
105
|
+
An explanation of the options used in the [`api_model`](doc/api_model.md) example above:
|
106
|
+
* `base_query` - Limit data exposed by the API based on context (e.g. current user).
|
107
|
+
|
108
|
+
An explanation of the options used in the [`api_attributes`](doc/api_attributes.md) example above:
|
97
109
|
* `filter` - Allow filtering by query string parameters (e.g. `?id=123`).
|
98
110
|
* `sort` - Allow use of this column in the sort_by parameter.
|
99
111
|
* `read_only` - Disallow column updates (via `POST`, `PUT`, or `PATCH`).
|
@@ -188,6 +188,9 @@ module ModelApi
|
|
188
188
|
default_link_options = request.params.to_h.symbolize_keys
|
189
189
|
opts[:collection_link_options] ||= default_link_options
|
190
190
|
opts[:object_link_options] ||= default_link_options
|
191
|
+
if default_link_options[:exclude_associations].present?
|
192
|
+
opts[:exclude_associations] ||= default_link_options[:exclude_associations]
|
193
|
+
end
|
191
194
|
end
|
192
195
|
opts[:options_initialized] ||= true
|
193
196
|
opts
|
data/lib/model-api/utils.rb
CHANGED
@@ -419,10 +419,49 @@ module ModelApi
|
|
419
419
|
includes << attr_metadata[:key] if attr_metadata[:type] == :association
|
420
420
|
end
|
421
421
|
includes = includes.compact.uniq
|
422
|
+
includes = remove_excluded_associations(includes, opts)
|
422
423
|
collection = collection.includes(includes) if includes.present?
|
423
424
|
collection
|
424
425
|
end
|
425
426
|
|
427
|
+
# Does not eager load associations mentioned in the exclude_associations
|
428
|
+
# array defined by user.
|
429
|
+
def remove_excluded_associations(includes, opts)
|
430
|
+
includes_dup = includes.compact.uniq.deep_dup
|
431
|
+
exclude_associations = opts[:exclude_associations]
|
432
|
+
return includes_dup unless exclude_associations.present?
|
433
|
+
exclude_associations.each do |association|
|
434
|
+
remove_association_from_array(includes_dup, association.to_sym)
|
435
|
+
end
|
436
|
+
includes_dup
|
437
|
+
end
|
438
|
+
|
439
|
+
# If the association is present in array form (in collection_includes) delete it.
|
440
|
+
# Then loop over the array elements to remove the association incase of nested associations.
|
441
|
+
def remove_association_from_array(array_collection, association)
|
442
|
+
array_collection.delete(association)
|
443
|
+
array_collection.each_with_index do |collection, i|
|
444
|
+
if collection.is_a?(Hash)
|
445
|
+
array_collection[i] = remove_association_from_hash(collection, association)
|
446
|
+
end
|
447
|
+
end
|
448
|
+
array_collection
|
449
|
+
end
|
450
|
+
|
451
|
+
# Incase of nested associations (in collection_inlcudes) delete the key with the association name
|
452
|
+
# and then loop over the collection to delete associations present as element of the array if any
|
453
|
+
def remove_association_from_hash(hash_collection, association)
|
454
|
+
if hash_collection.keys.include?(association)
|
455
|
+
hash_collection.delete(association)
|
456
|
+
else
|
457
|
+
hash_collection.each do |key, value|
|
458
|
+
hash_collection[key] =
|
459
|
+
remove_association_from_array(value, association) if value.is_a?(Array)
|
460
|
+
end
|
461
|
+
end
|
462
|
+
hash_collection
|
463
|
+
end
|
464
|
+
|
426
465
|
def find_class(obj, opts = {})
|
427
466
|
return nil if obj.nil?
|
428
467
|
opts[:class] || (obj.respond_to?(:klass) ? obj.klass : obj.class)
|
@@ -459,6 +498,13 @@ module ModelApi
|
|
459
498
|
metadata
|
460
499
|
end
|
461
500
|
|
501
|
+
def exclude_associations_metadata(metadata, obj, opts = {})
|
502
|
+
exclude_associations = opts[:exclude_associations].try(:map, &:to_sym)
|
503
|
+
if exclude_associations.present?
|
504
|
+
(exclude_associations.include?(obj.table_name) || exclude_associations.include?(metadata[:key]))
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
462
508
|
def include_item?(metadata, obj, operation, opts = {})
|
463
509
|
return false unless metadata.is_a?(Hash)
|
464
510
|
return false unless include_item_meets_admin_criteria?(metadata, obj, operation, opts)
|
@@ -467,6 +513,7 @@ module ModelApi
|
|
467
513
|
return eval_bool(obj, metadata[:sort], opts) if operation == :sort
|
468
514
|
return false unless include_item_meets_read_write_criteria?(metadata, obj, operation, opts)
|
469
515
|
return false unless include_item_meets_incl_excl_criteria?(metadata, obj, operation, opts)
|
516
|
+
return false if exclude_associations_metadata(metadata, obj, opts)
|
470
517
|
true
|
471
518
|
end
|
472
519
|
|
data/model-api.gemspec
CHANGED
@@ -3,7 +3,7 @@ $:.unshift lib unless $:.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = 'model-api'
|
6
|
-
s.version = '0.8.
|
6
|
+
s.version = '0.8.11'
|
7
7
|
s.summary = 'Create easy REST API\'s using metadata inside your ActiveRecord models'
|
8
8
|
s.description = 'Ruby gem allowing Ruby on Rails developers to create REST API’s using ' \
|
9
9
|
'metadata defined inside their ActiveRecord models.'
|
metadata
CHANGED
@@ -1,61 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Mead
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: open-api
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.8.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.8.4
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec-rails
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '3.5'
|
48
|
-
- -
|
48
|
+
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: 3.5.2
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- - ~>
|
55
|
+
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '3.5'
|
58
|
-
- -
|
58
|
+
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: 3.5.2
|
61
61
|
description: Ruby gem allowing Ruby on Rails developers to create REST API’s using
|
@@ -90,17 +90,17 @@ require_paths:
|
|
90
90
|
- lib
|
91
91
|
required_ruby_version: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
|
-
- -
|
93
|
+
- - ">="
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
|
-
- -
|
98
|
+
- - ">="
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '0'
|
101
101
|
requirements: []
|
102
102
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
103
|
+
rubygems_version: 2.5.2
|
104
104
|
signing_key:
|
105
105
|
specification_version: 4
|
106
106
|
summary: Create easy REST API's using metadata inside your ActiveRecord models
|