repia 0.2.0 → 0.3.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 +4 -4
- data/README.md +4 -4
- data/lib/repia.rb +5 -5
- data/lib/repia/controller.rb +1 -0
- data/lib/repia/controller/base.rb +32 -0
- data/lib/repia/helper.rb +1 -0
- data/lib/repia/helper/base.rb +82 -0
- data/lib/repia/middlewares.rb +1 -30
- data/lib/repia/middlewares/http_method_not_allowed.rb +32 -0
- data/lib/repia/support.rb +1 -0
- data/lib/repia/support/uuid_model.rb +31 -0
- data/lib/repia/version.rb +1 -1
- data/test/dummy/app/controllers/application_controller.rb +1 -1
- data/test/dummy/app/models/unique_model.rb +1 -1
- data/test/repia_middlewares_test.rb +2 -2
- metadata +42 -40
- data/lib/repia/base_controller.rb +0 -33
- data/lib/repia/base_helper.rb +0 -83
- data/lib/repia/uuid_model.rb +0 -28
- data/test/dummy/log/test.log +0 -1783
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49ce47f5fd78ab42d146e3609a18d5a4f52131e8
|
4
|
+
data.tar.gz: 650e067cdeccb5b2d1eb89543232a5017b64784b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52c031db5fd4279284e87cf72c6633feb8af94516ff0df899cb25b119c03ed074bbad07911749081bd6b61992300336028d962ba741ebf2d9d09e2ac47aaf59f
|
7
|
+
data.tar.gz: 85c3846603cf84ad6d20a2843ea4bbb7de5cf7e10534847f6478a01e2bdb603263c924c6ad1981b8c8ea33f1836ce47c2e27484ac45aa8fd31945f7265f3e333
|
data/README.md
CHANGED
@@ -16,7 +16,7 @@ Add `gem 'repia'` to your project `Gemfile`.
|
|
16
16
|
|
17
17
|
Edit `application_controller.rb` as the following:
|
18
18
|
|
19
|
-
class ApplicationController < Repia::
|
19
|
+
class ApplicationController < Repia::Controller::Base
|
20
20
|
end
|
21
21
|
|
22
22
|
This will allow all controllers in the project to inherit from
|
@@ -26,13 +26,13 @@ pre-defined HTTP errors.
|
|
26
26
|
Next, update all models that need UUID as a primary identifier:
|
27
27
|
|
28
28
|
class Something < ActiveRecord::Base
|
29
|
-
include Repia::UUIDModel
|
29
|
+
include Repia::Support::UUIDModel
|
30
30
|
end
|
31
31
|
|
32
32
|
This will trigger UUID generation before a record object is created. Note
|
33
33
|
that migration must look similar to this:
|
34
34
|
|
35
|
-
class CreateSomethings < ActiveRecord::Migration
|
35
|
+
class CreateSomethings < ActiveRecord::Migration[5.0]
|
36
36
|
def change
|
37
37
|
create_table :somethings, id: false do |t|
|
38
38
|
t.string :uuid, primary_key: true, null: false
|
@@ -59,7 +59,7 @@ template, it will return a simple JSON response with a status of 405.
|
|
59
59
|
|
60
60
|
### Routing Error
|
61
61
|
|
62
|
-
Routing errors can be caught using `
|
62
|
+
Routing errors can be caught using `Repia::Controller::Base#exceptions_app`. To
|
63
63
|
configure it, add this to `config/application.rb`:
|
64
64
|
|
65
65
|
config.exceptions_app = lambda {|env| ApplicationController.action(:exceptions_app).call(env)}
|
data/lib/repia.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require_relative 'repia/errors'
|
2
|
+
require_relative 'repia/middlewares'
|
3
|
+
require_relative 'repia/support'
|
4
|
+
require_relative 'repia/helper'
|
5
|
+
require_relative 'repia/controller'
|
6
6
|
|
7
7
|
module Repia
|
8
8
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'controller/base'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative '../errors'
|
3
|
+
require_relative '../helper/base'
|
4
|
+
|
5
|
+
module Repia
|
6
|
+
module Controller
|
7
|
+
##
|
8
|
+
# This controller is a base controller for RESTful API. Two primary
|
9
|
+
# features:
|
10
|
+
#
|
11
|
+
# - Error (exception) handling
|
12
|
+
# - Options request handling
|
13
|
+
#
|
14
|
+
class Base < ActionController::Base
|
15
|
+
include Helper::Base
|
16
|
+
|
17
|
+
# This is a catch-all.
|
18
|
+
rescue_from StandardError do |exception|
|
19
|
+
logger.error exception.message
|
20
|
+
render_error 500, "Unknown error occurred: #{exception.message}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Catch all manually thrown HTTP errors (predefined by repia)
|
24
|
+
rescue_from Errors::HTTPError do |exception|
|
25
|
+
status_code = exception.class.const_get("STATUS_CODE")
|
26
|
+
message = exception.message || exception.class::MESSAGE
|
27
|
+
logger.error "#{status_code} - #{message}"
|
28
|
+
render_error status_code, message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/repia/helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'helper/base'
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require_relative '../errors'
|
2
|
+
|
3
|
+
module Repia
|
4
|
+
module Helper
|
5
|
+
##
|
6
|
+
# This helper module includes methods that are essential for building a
|
7
|
+
# RESTful API.
|
8
|
+
#
|
9
|
+
module Base
|
10
|
+
|
11
|
+
##
|
12
|
+
# Use this as an action triggered by exceptions_app to return a JSON
|
13
|
+
# response to any middleware level exceptions.
|
14
|
+
#
|
15
|
+
# For example,
|
16
|
+
#
|
17
|
+
# config.exceptions_app = lambda { |env|
|
18
|
+
# ApplicationController.action(:exceptions_app).call(env)
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
def exceptions_app
|
22
|
+
ex_wrapper = ActionDispatch::ExceptionWrapper.new(Rails.env, @exception)
|
23
|
+
status = ex_wrapper.status_code.to_i
|
24
|
+
error = Errors::STATUS_CODE_TO_ERROR[status]
|
25
|
+
if error
|
26
|
+
message = error::MESSAGE
|
27
|
+
else
|
28
|
+
# :nocov:
|
29
|
+
status = 500
|
30
|
+
message = "Unknown error"
|
31
|
+
# :nocov:
|
32
|
+
end
|
33
|
+
render_error status, message
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Renders a generic OPTIONS response. The actual controller must
|
38
|
+
# override this action if desired to have specific OPTIONS handling
|
39
|
+
# logic.
|
40
|
+
#
|
41
|
+
def options
|
42
|
+
# echo back access-control-request-headers
|
43
|
+
if request.headers["Access-Control-Request-Headers"]
|
44
|
+
response["Access-Control-Allow-Headers"] =
|
45
|
+
request.headers["Access-Control-Request-Headers"]
|
46
|
+
end
|
47
|
+
render body: "", status: 200
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Renders a single error.
|
52
|
+
#
|
53
|
+
def render_error(status, msg)
|
54
|
+
render json: {errors: [msg]}, status: status
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Renders multiple errors
|
59
|
+
#
|
60
|
+
def render_errors(status, msgs)
|
61
|
+
render json: {errors: msgs}, status: status
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Finds an object by model and UUID and throws an error (which will be
|
66
|
+
# caught and re-thrown as an HTTP error) if the object does not exist.
|
67
|
+
# The error can be optionally suppresed by specifying nil to error.
|
68
|
+
#
|
69
|
+
# An Repia::Errors::NotFound is raised if specified to do so when
|
70
|
+
# the object could not be found using the uuid.
|
71
|
+
#
|
72
|
+
def find_object(model, uuid, error: Errors::NotFound)
|
73
|
+
logger.debug("Attempting to get #{model.name} #{uuid}")
|
74
|
+
obj = model.find_by_uuid(uuid)
|
75
|
+
if obj.nil? && !error.nil?
|
76
|
+
raise error, "#{model.name} #{uuid} cannot be found"
|
77
|
+
end
|
78
|
+
return obj
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/repia/middlewares.rb
CHANGED
@@ -1,30 +1 @@
|
|
1
|
-
|
2
|
-
##
|
3
|
-
# This class serves as a middleware to handle Method Not Allowed error
|
4
|
-
# (which is not handled by show_exceptions for some reason).
|
5
|
-
#
|
6
|
-
# Code was excerpted from https://gist.github.com/viola/1243572 and was
|
7
|
-
# modified to serve a JSON response.
|
8
|
-
#
|
9
|
-
# Add it after ActionDispatch::RequestId to keep the request ID in the
|
10
|
-
# response headers.
|
11
|
-
#
|
12
|
-
class HttpMethodNotAllowed
|
13
|
-
def initialize(app)
|
14
|
-
@app = app
|
15
|
-
end
|
16
|
-
|
17
|
-
def call(env)
|
18
|
-
if !ActionDispatch::Request::HTTP_METHODS.include?(env["REQUEST_METHOD"].upcase)
|
19
|
-
Rails.logger.info("ActionController::UnknownHttpMethod: #{env.inspect}")
|
20
|
-
[405,
|
21
|
-
{"Content-Type" => "application/json; charset=utf-8"},
|
22
|
-
[JSON.generate({errors: ["Method not allowed"]})]
|
23
|
-
]
|
24
|
-
else
|
25
|
-
@status, @headers, @response = @app.call(env)
|
26
|
-
[@status, @headers, @response]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
1
|
+
require_relative 'middlewares/http_method_not_allowed'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Repia
|
2
|
+
module Middlewares
|
3
|
+
##
|
4
|
+
# This class serves as a middleware to handle Method Not Allowed error
|
5
|
+
# (which is not handled by show_exceptions for some reason).
|
6
|
+
#
|
7
|
+
# Code was excerpted from https://gist.github.com/viola/1243572 and was
|
8
|
+
# modified to serve a JSON response.
|
9
|
+
#
|
10
|
+
# Add it after ActionDispatch::RequestId to keep the request ID in the
|
11
|
+
# response headers.
|
12
|
+
#
|
13
|
+
class HttpMethodNotAllowed
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
if !ActionDispatch::Request::HTTP_METHODS.include?(env["REQUEST_METHOD"].upcase)
|
20
|
+
Rails.logger.info("ActionController::UnknownHttpMethod: #{env.inspect}")
|
21
|
+
[405,
|
22
|
+
{"Content-Type" => "application/json; charset=utf-8"},
|
23
|
+
[JSON.generate({errors: ["Method not allowed"]})]
|
24
|
+
]
|
25
|
+
else
|
26
|
+
@status, @headers, @response = @app.call(env)
|
27
|
+
[@status, @headers, @response]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'support/uuid_model'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
module Repia
|
3
|
+
|
4
|
+
module Support
|
5
|
+
|
6
|
+
##
|
7
|
+
# This module is a mixin that allows the model to use UUIDs instead of
|
8
|
+
# normal IDs. By including this module, the model class declares that the
|
9
|
+
# primary key is called "uuid" and an UUID is generated right before
|
10
|
+
# save(). You may assign an UUID prior to save, in which case, no new UUID
|
11
|
+
# will be generated.
|
12
|
+
#
|
13
|
+
module UUIDModel
|
14
|
+
|
15
|
+
##
|
16
|
+
# Triggered when this module is included.
|
17
|
+
#
|
18
|
+
def self.included(klass)
|
19
|
+
klass.primary_key = "uuid"
|
20
|
+
klass.before_create :generate_uuid
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Generates an UUID for the model object.
|
25
|
+
#
|
26
|
+
def generate_uuid()
|
27
|
+
self.uuid = UUIDTools::UUID.timestamp_create().to_s if self.uuid.nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/repia/version.rb
CHANGED
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
class RepiaTest < ActiveSupport::TestCase
|
4
4
|
test "HttpMethodNotAllowed middleware throws 405 for invalid HTTP method" do
|
5
5
|
app = lambda {|env| [200, {}, [""]]}
|
6
|
-
stack = Repia::HttpMethodNotAllowed.new(app)
|
6
|
+
stack = Repia::Middlewares::HttpMethodNotAllowed.new(app)
|
7
7
|
request = Rack::MockRequest.new(stack)
|
8
8
|
response = request.request("DOESNOTEXIST", "/users")
|
9
9
|
assert response.headers["Content-Type"].include?("application/json")
|
@@ -12,7 +12,7 @@ class RepiaTest < ActiveSupport::TestCase
|
|
12
12
|
|
13
13
|
test "HttpMethodNotAllowed middleware does not throw 405 for valid HTTP method" do
|
14
14
|
app = lambda {|env| [200, {}, [""]]}
|
15
|
-
stack = Repia::HttpMethodNotAllowed.new(app)
|
15
|
+
stack = Repia::Middlewares::HttpMethodNotAllowed.new(app)
|
16
16
|
request = Rack::MockRequest.new(stack)
|
17
17
|
response = request.request("GET", "/users")
|
18
18
|
assert_equal 200, response.status.to_i
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: repia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David An
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -92,11 +92,15 @@ files:
|
|
92
92
|
- README.md
|
93
93
|
- Rakefile
|
94
94
|
- lib/repia.rb
|
95
|
-
- lib/repia/
|
96
|
-
- lib/repia/
|
95
|
+
- lib/repia/controller.rb
|
96
|
+
- lib/repia/controller/base.rb
|
97
97
|
- lib/repia/errors.rb
|
98
|
+
- lib/repia/helper.rb
|
99
|
+
- lib/repia/helper/base.rb
|
98
100
|
- lib/repia/middlewares.rb
|
99
|
-
- lib/repia/
|
101
|
+
- lib/repia/middlewares/http_method_not_allowed.rb
|
102
|
+
- lib/repia/support.rb
|
103
|
+
- lib/repia/support/uuid_model.rb
|
100
104
|
- lib/repia/version.rb
|
101
105
|
- lib/tasks/repia_tasks.rake
|
102
106
|
- test/dummy/README.rdoc
|
@@ -137,7 +141,6 @@ files:
|
|
137
141
|
- test/dummy/db/migrate/20160423030023_create_unique_models.rb
|
138
142
|
- test/dummy/db/schema.rb
|
139
143
|
- test/dummy/db/test.sqlite3
|
140
|
-
- test/dummy/log/test.log
|
141
144
|
- test/dummy/public/404.html
|
142
145
|
- test/dummy/public/422.html
|
143
146
|
- test/dummy/public/500.html
|
@@ -175,54 +178,53 @@ signing_key:
|
|
175
178
|
specification_version: 4
|
176
179
|
summary: Rails Essential Plug-in for API
|
177
180
|
test_files:
|
178
|
-
- test/
|
179
|
-
- test/
|
181
|
+
- test/test_helper.rb
|
182
|
+
- test/repia_unique_model_test.rb
|
183
|
+
- test/dummy/README.rdoc
|
184
|
+
- test/dummy/app/views/layouts/application.html.erb
|
185
|
+
- test/dummy/app/models/unique_model.rb
|
180
186
|
- test/dummy/app/assets/stylesheets/application.css
|
181
187
|
- test/dummy/app/assets/stylesheets/dummies.css
|
182
|
-
- test/dummy/app/
|
183
|
-
- test/dummy/app/
|
188
|
+
- test/dummy/app/assets/javascripts/application.js
|
189
|
+
- test/dummy/app/assets/javascripts/dummies.js
|
184
190
|
- test/dummy/app/helpers/dummies_helper.rb
|
185
|
-
- test/dummy/app/
|
186
|
-
- test/dummy/app/
|
187
|
-
- test/dummy/
|
188
|
-
- test/dummy/
|
189
|
-
- test/dummy/
|
190
|
-
- test/dummy/
|
191
|
-
- test/dummy/
|
192
|
-
- test/dummy/config/
|
191
|
+
- test/dummy/app/helpers/application_helper.rb
|
192
|
+
- test/dummy/app/controllers/application_controller.rb
|
193
|
+
- test/dummy/Rakefile
|
194
|
+
- test/dummy/public/500.html
|
195
|
+
- test/dummy/public/404.html
|
196
|
+
- test/dummy/public/favicon.ico
|
197
|
+
- test/dummy/public/422.html
|
198
|
+
- test/dummy/config/locales/en.yml
|
193
199
|
- test/dummy/config/database.yml
|
194
|
-
- test/dummy/config/environment.rb
|
195
|
-
- test/dummy/config/environments/development.rb
|
196
200
|
- test/dummy/config/environments/production.rb
|
197
201
|
- test/dummy/config/environments/test.rb
|
202
|
+
- test/dummy/config/environments/development.rb
|
203
|
+
- test/dummy/config/environment.rb
|
204
|
+
- test/dummy/config/routes.rb
|
198
205
|
- test/dummy/config/initializers/assets.rb
|
199
|
-
- test/dummy/config/initializers/backtrace_silencers.rb
|
200
|
-
- test/dummy/config/initializers/cookies_serializer.rb
|
201
|
-
- test/dummy/config/initializers/filter_parameter_logging.rb
|
202
206
|
- test/dummy/config/initializers/inflections.rb
|
203
207
|
- test/dummy/config/initializers/mime_types.rb
|
204
|
-
- test/dummy/config/initializers/session_store.rb
|
205
208
|
- test/dummy/config/initializers/wrap_parameters.rb
|
206
|
-
- test/dummy/config/
|
207
|
-
- test/dummy/config/
|
209
|
+
- test/dummy/config/initializers/backtrace_silencers.rb
|
210
|
+
- test/dummy/config/initializers/cookies_serializer.rb
|
211
|
+
- test/dummy/config/initializers/session_store.rb
|
212
|
+
- test/dummy/config/initializers/filter_parameter_logging.rb
|
208
213
|
- test/dummy/config/secrets.yml
|
209
|
-
- test/dummy/config.
|
214
|
+
- test/dummy/config/application.rb
|
215
|
+
- test/dummy/config/boot.rb
|
210
216
|
- test/dummy/db/development.sqlite3
|
217
|
+
- test/dummy/db/test.sqlite3
|
211
218
|
- test/dummy/db/migrate/20160423030023_create_unique_models.rb
|
212
219
|
- test/dummy/db/schema.rb
|
213
|
-
- test/dummy/
|
214
|
-
- test/dummy/log/test.log
|
215
|
-
- test/dummy/public/404.html
|
216
|
-
- test/dummy/public/422.html
|
217
|
-
- test/dummy/public/500.html
|
218
|
-
- test/dummy/public/favicon.ico
|
219
|
-
- test/dummy/Rakefile
|
220
|
-
- test/dummy/README.rdoc
|
221
|
-
- test/dummy/test/controllers/dummies_controller_test.rb
|
220
|
+
- test/dummy/config.ru
|
222
221
|
- test/dummy/test/fixtures/unique_models.yml
|
223
222
|
- test/dummy/test/models/unique_model_test.rb
|
224
|
-
- test/
|
225
|
-
- test/
|
223
|
+
- test/dummy/test/controllers/dummies_controller_test.rb
|
224
|
+
- test/dummy/bin/bundle
|
225
|
+
- test/dummy/bin/rails
|
226
|
+
- test/dummy/bin/setup
|
227
|
+
- test/dummy/bin/rake
|
226
228
|
- test/repia_test.rb
|
227
|
-
- test/
|
228
|
-
- test/
|
229
|
+
- test/repia_middlewares_test.rb
|
230
|
+
- test/repia_base_controller_test.rb
|