mini_api 0.1.0
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +182 -0
- data/Rakefile +5 -0
- data/lib/mini_api/default_responder.rb +24 -0
- data/lib/mini_api/exceptions/kaminari_not_installed.rb +5 -0
- data/lib/mini_api/locales/en.yml +13 -0
- data/lib/mini_api/model_responder.rb +61 -0
- data/lib/mini_api/railtie.rb +10 -0
- data/lib/mini_api/relation_responder.rb +51 -0
- data/lib/mini_api/responder.rb +38 -0
- data/lib/mini_api/serialization.rb +16 -0
- data/lib/mini_api/version.rb +5 -0
- data/lib/mini_api.rb +25 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b21a5cc35f98d6a21450a738d876b0c7fee94d36113e0c3999f15df17c59f643
|
4
|
+
data.tar.gz: d60bf59a2ca1d64d4157fa46e9d770ed6b748e7895aa77bb2410936e09de91a6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dcb3b028b14506c7c15dd2df893c25af5dabdfd7f47ca8781c32ebaeb7cf2a3b6c5d17be9a2befeeb2c0c7cc996c774230ba1f9fe11b07464f1a50cd7a6e4a9a
|
7
|
+
data.tar.gz: 2af62824d289dd78d9bb9e7a813a319179c56229ed6443e64746e65cf687e796e519a59d00c20c2f9745a3950d455111e0291eb6c7f05e5cd2cd6b635b9de7ab
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 Leon Cruz
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+

|
2
|
+
[](https://codeclimate.com/github/leoncruz/api-responder/maintainability)
|
3
|
+
[](https://codeclimate.com/github/leoncruz/api-responder/test_coverage)
|
4
|
+
|
5
|
+
# Mini Api
|
6
|
+
A gem to standardize json responses in Rails applications, highly inspired on [Responders](https:github.com/heartcombo/responders)
|
7
|
+
|
8
|
+
## Table of Contents
|
9
|
+
- [Usage](#usage)
|
10
|
+
- [Respondering json](#respondering-json)
|
11
|
+
- [Success and failure actions](#success-and-failure-actions)
|
12
|
+
- [Overriding response](#overriding-response)
|
13
|
+
- [Pagination](#pagination)
|
14
|
+
- [Contributing](#contributing)
|
15
|
+
- [License](#license)
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem "mini_api"
|
22
|
+
```
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
```bash
|
26
|
+
$ bundle
|
27
|
+
```
|
28
|
+
|
29
|
+
Your must install [Kaminari](https://github.com/kaminari/kaminari) to handle pagination
|
30
|
+
and [Active Model Serializers](http://github.com/rails-api/active_model_serializers) to handle data serialization
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
After install the gem, include the `MiniApi` module into your `ApplicationController` or other parent controller
|
35
|
+
```ruby
|
36
|
+
class ApplicationController < ActionController::Base
|
37
|
+
include MiniApi
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
This include three methods in your controllers: `render_json`, `page` and `per_page`
|
42
|
+
|
43
|
+
The methods `page` and `per_page` will handle the params: `page` and `per_page` respectively
|
44
|
+
|
45
|
+
### Respondering json
|
46
|
+
|
47
|
+
In your controller you only need to call the `render_json` method informing what you want to send. Example:
|
48
|
+
```ruby
|
49
|
+
class UsersController < ApplicationController
|
50
|
+
def show
|
51
|
+
user = User.find(params[:id])
|
52
|
+
|
53
|
+
render_json user
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
The generated json will be like:
|
59
|
+
```json
|
60
|
+
{
|
61
|
+
"success": true,
|
62
|
+
"data": { }, // user data here
|
63
|
+
"message": ""
|
64
|
+
}
|
65
|
+
```
|
66
|
+
|
67
|
+
If your data is a `ActiveRecord::Relation`, the behavior is the same, with pagination data added to `meta` key
|
68
|
+
```ruby
|
69
|
+
class UsersController < ApplicationController
|
70
|
+
def index
|
71
|
+
users = User.all
|
72
|
+
|
73
|
+
render_json users
|
74
|
+
end
|
75
|
+
end
|
76
|
+
```
|
77
|
+
The response will be like:
|
78
|
+
```json
|
79
|
+
{
|
80
|
+
"success": true,
|
81
|
+
"data": { }, // users here
|
82
|
+
"meta": {
|
83
|
+
"current_page": 1,
|
84
|
+
"next_page": 2,
|
85
|
+
"prev_page": null,
|
86
|
+
"total_pages": 10,
|
87
|
+
"total_records": 100
|
88
|
+
}
|
89
|
+
}
|
90
|
+
```
|
91
|
+
|
92
|
+
### Success and failure actions
|
93
|
+
|
94
|
+
Many times, our controller actions need to persist or validate some data coming from request, the default approach to do that is like:
|
95
|
+
```ruby
|
96
|
+
class UsersController < ApplicationController
|
97
|
+
def new
|
98
|
+
user = User.new(user_params)
|
99
|
+
|
100
|
+
if user.save
|
101
|
+
render json: user, status: :created
|
102
|
+
else
|
103
|
+
render json: user.errors.messages, status: :unprocessable_entity
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
But, with `mini_api`, you could simplify the action doing like:
|
109
|
+
```ruby
|
110
|
+
class UsersController < ApplicationController
|
111
|
+
def new
|
112
|
+
user = User.new(user_params)
|
113
|
+
|
114
|
+
user.save
|
115
|
+
|
116
|
+
render_json user
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
If the `user` was created successfully, then the response will be like:
|
121
|
+
```json
|
122
|
+
{
|
123
|
+
"success": true,
|
124
|
+
"data": { }, // user data here
|
125
|
+
"message": "User was successfully created."
|
126
|
+
}
|
127
|
+
```
|
128
|
+
with `status_code` 201
|
129
|
+
|
130
|
+
But, if user is not valid, then the response will be like:
|
131
|
+
```json
|
132
|
+
{
|
133
|
+
"success": false,
|
134
|
+
"errors": { }, // user errors here
|
135
|
+
"message": "User could not be created."
|
136
|
+
}
|
137
|
+
```
|
138
|
+
witht `status_code` 422
|
139
|
+
|
140
|
+
The `message` key is different based on actions on informed model: create, update, and destroy
|
141
|
+
|
142
|
+
You can respond any type of data, but ActiveRecord/ActiveModel::Model and ActiveRecord::Relation has a special treatment as shown above
|
143
|
+
|
144
|
+
## Overriding response
|
145
|
+
|
146
|
+
You can override the `status`, `message` and `sucess` keys simply informing values to `render_json`. Example:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
class UsersController < ApplicationController
|
150
|
+
def new
|
151
|
+
user = User.new(user_params)
|
152
|
+
|
153
|
+
if user.save
|
154
|
+
render_json user, message: 'custom message'
|
155
|
+
else
|
156
|
+
render_json user.errors.messages, status: :bad_request, success: true
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
```
|
161
|
+
This way, the response will contain the informed values
|
162
|
+
|
163
|
+
## Pagination
|
164
|
+
|
165
|
+
This plugin handle pagination using `kaminari` gem. The params to evaluate pagination are `page` and `per_page`
|
166
|
+
|
167
|
+
if no page is informed, by default will use page `1`
|
168
|
+
|
169
|
+
Default value of `per_page` is `25`. Only specific values are permitted to `per_page`, they are: 10, 25, 50, 100
|
170
|
+
|
171
|
+
If the value it is none of those, so the default value is used
|
172
|
+
|
173
|
+
## Contributing
|
174
|
+
|
175
|
+
1. Fork it
|
176
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
177
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
178
|
+
4. Push to the branch (git push origin my-new-feature)
|
179
|
+
5. Create new Pull Request
|
180
|
+
|
181
|
+
## License
|
182
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MiniApi
|
4
|
+
class DefaultResponder
|
5
|
+
def initialize(controller, resource, options = {})
|
6
|
+
@controller = controller
|
7
|
+
@resource = resource
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond
|
12
|
+
success = @options[:success] != false
|
13
|
+
|
14
|
+
@controller.render(
|
15
|
+
json: {
|
16
|
+
success: success,
|
17
|
+
data: @resource,
|
18
|
+
message: @options[:message] || nil
|
19
|
+
},
|
20
|
+
status: @options[:status] || :ok
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
en:
|
2
|
+
mini_api:
|
3
|
+
messages:
|
4
|
+
actions:
|
5
|
+
create:
|
6
|
+
notice: '%{resource_name} was successfully created.'
|
7
|
+
alert: '%{resource_name} could not be created.'
|
8
|
+
update:
|
9
|
+
notice: '%{resource_name} was successfully updated.'
|
10
|
+
alert: '%{resource_name} could not be updated.'
|
11
|
+
destroy:
|
12
|
+
notice: '%{resource_name} was successfully destroyed.'
|
13
|
+
alert: '%{resource_name} could not be destroyed.'
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mini_api/serialization'
|
4
|
+
|
5
|
+
module MiniApi
|
6
|
+
# class to handle json render of ActiveRecord::Base instances and ActiveModel::Model's
|
7
|
+
class ModelResponder
|
8
|
+
include Serialization
|
9
|
+
|
10
|
+
def initialize(controller, resource, options = {})
|
11
|
+
@controller = controller
|
12
|
+
@resource = resource
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond
|
17
|
+
body = {
|
18
|
+
success: resource_has_errors? == false,
|
19
|
+
message: @options[:message] || default_message
|
20
|
+
}
|
21
|
+
|
22
|
+
body =
|
23
|
+
if resource_has_errors?
|
24
|
+
{ errors: @resource.errors.messages }.merge(body)
|
25
|
+
else
|
26
|
+
{ data: serialiable_body(@resource) }.merge(body)
|
27
|
+
end
|
28
|
+
|
29
|
+
@controller.render json: body, status: status_code
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def resource_has_errors?
|
35
|
+
!@resource.errors.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def status_code
|
39
|
+
return @options[:status] if @options[:status].present?
|
40
|
+
|
41
|
+
return :unprocessable_entity if resource_has_errors?
|
42
|
+
|
43
|
+
return :created if @resource.previously_new_record?
|
44
|
+
|
45
|
+
return :no_content unless @resource.persisted?
|
46
|
+
|
47
|
+
:ok
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_message
|
51
|
+
kind = resource_has_errors? ? 'alert' : 'notice'
|
52
|
+
|
53
|
+
I18n.t(
|
54
|
+
kind,
|
55
|
+
scope: [:mini_api, :messages, :actions, @controller.action_name],
|
56
|
+
resource_name: @resource.class.model_name.human,
|
57
|
+
default: ''
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mini_api/exceptions/kaminari_not_installed'
|
4
|
+
require 'mini_api/serialization'
|
5
|
+
|
6
|
+
module MiniApi
|
7
|
+
class RelationResponder
|
8
|
+
include Serialization
|
9
|
+
|
10
|
+
def initialize(controller, resource, options = {})
|
11
|
+
@controller = controller
|
12
|
+
@resource = resource
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond
|
17
|
+
meta, collection = extract_meta_and_collection
|
18
|
+
|
19
|
+
@controller.render json: {
|
20
|
+
success: @options[:success] || true,
|
21
|
+
data: collection,
|
22
|
+
meta: meta
|
23
|
+
}, status: @options[:status]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def extract_meta_and_collection
|
29
|
+
collection = transform_resource_to_collection
|
30
|
+
|
31
|
+
[
|
32
|
+
{
|
33
|
+
current_page: collection.current_page,
|
34
|
+
next_page: collection.next_page,
|
35
|
+
prev_page: collection.prev_page,
|
36
|
+
total_pages: collection.total_pages,
|
37
|
+
total_records: collection.total_count
|
38
|
+
},
|
39
|
+
serialiable_body(collection)
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def transform_resource_to_collection
|
44
|
+
unless defined?(Kaminari)
|
45
|
+
raise KaminariNotInstalled, 'The Kaminari gem is not installed. Install to perform pagination operations'
|
46
|
+
end
|
47
|
+
|
48
|
+
@resource.page(@controller.page).per(@controller.per_page)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mini_api/default_responder'
|
4
|
+
require 'mini_api/model_responder'
|
5
|
+
require 'mini_api/relation_responder'
|
6
|
+
|
7
|
+
module MiniApi
|
8
|
+
class Responder
|
9
|
+
def initialize(controller, resource, options = {})
|
10
|
+
@controller = controller
|
11
|
+
@resource = resource
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def respond
|
16
|
+
case @resource
|
17
|
+
when ActiveRecord::Relation
|
18
|
+
relation_responder.respond
|
19
|
+
when ActiveRecord::Base, ActiveModel::Model
|
20
|
+
model_responder.respond
|
21
|
+
else
|
22
|
+
default_responder.respond
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def relation_responder
|
27
|
+
RelationResponder.new(@controller, @resource, @options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def model_responder
|
31
|
+
ModelResponder.new(@controller, @resource, @options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def default_responder
|
35
|
+
DefaultResponder.new(@controller, @resource, @options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MiniApi
|
4
|
+
#
|
5
|
+
# This module is responsible to handler integration with Active Model Serialier gem
|
6
|
+
# call the +get_serializer+ method of controller implemented by gem
|
7
|
+
# to find the serializer of informed object.
|
8
|
+
|
9
|
+
module Serialization
|
10
|
+
def serialiable_body(resource)
|
11
|
+
return resource unless defined?(ActiveModel::Serializer)
|
12
|
+
|
13
|
+
@controller.get_serializer(resource)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/mini_api.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mini_api/railtie'
|
4
|
+
require 'mini_api/responder'
|
5
|
+
|
6
|
+
# Entrypoint module
|
7
|
+
module MiniApi
|
8
|
+
def render_json(resource, options = {})
|
9
|
+
responder = Responder.new(self, resource, options)
|
10
|
+
|
11
|
+
responder.respond
|
12
|
+
end
|
13
|
+
|
14
|
+
def page
|
15
|
+
params[:page].to_i || 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def per_page
|
19
|
+
if params[:per_page].to_i.in?([10, 25, 50, 100])
|
20
|
+
params[:per_page]
|
21
|
+
else
|
22
|
+
25
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mini_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leon Cruz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-06-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.5
|
27
|
+
description: A collection of resources to create restful apis
|
28
|
+
email:
|
29
|
+
- leon.cruz.teixeira@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- MIT-LICENSE
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- lib/mini_api.rb
|
38
|
+
- lib/mini_api/default_responder.rb
|
39
|
+
- lib/mini_api/exceptions/kaminari_not_installed.rb
|
40
|
+
- lib/mini_api/locales/en.yml
|
41
|
+
- lib/mini_api/model_responder.rb
|
42
|
+
- lib/mini_api/railtie.rb
|
43
|
+
- lib/mini_api/relation_responder.rb
|
44
|
+
- lib/mini_api/responder.rb
|
45
|
+
- lib/mini_api/serialization.rb
|
46
|
+
- lib/mini_api/version.rb
|
47
|
+
homepage:
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata:
|
51
|
+
rubygems_mfa_required: 'true'
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubygems_version: 3.2.15
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: A collection of resources to create restful apis
|
71
|
+
test_files: []
|