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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 58b009fb035768295085359fa8691131240bc972
4
- data.tar.gz: cca0b9c1a35e7c92a489fe24362cae9128a019a8
3
+ metadata.gz: 49ce47f5fd78ab42d146e3609a18d5a4f52131e8
4
+ data.tar.gz: 650e067cdeccb5b2d1eb89543232a5017b64784b
5
5
  SHA512:
6
- metadata.gz: 8ac3b531337a59b00877e1e80ef38cf046bb0131db0a053971b64f1dca261219872dfa72b74525424f3504fcac9c02e024978aad4082c78fcea595d9d6b676ae
7
- data.tar.gz: e9a7c31828bdecbae836a3a53e9abba1c26ada136a7f046a53d21aa8fabbc2a92a4f55d14ce81dae5259a0843c5ac4e7ac7a4ccd0bf11fd30edf5ee4a4c4777b
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::BaseController
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 `BaseController#exceptions_app`. To
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)}
@@ -1,8 +1,8 @@
1
- require 'repia/errors'
2
- require 'repia/middlewares'
3
- require 'repia/uuid_model'
4
- require 'repia/base_helper'
5
- require 'repia/base_controller'
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
@@ -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
@@ -1,30 +1 @@
1
- module Repia
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
@@ -1,3 +1,3 @@
1
1
  module Repia
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,4 +1,4 @@
1
- class ApplicationController < Repia::BaseController
1
+ class ApplicationController < Repia::Controller::Base
2
2
  # Prevent CSRF attacks by raising an exception.
3
3
  # For APIs, you may want to use :null_session instead.
4
4
  protect_from_forgery with: :exception
@@ -1,4 +1,4 @@
1
1
  class UniqueModel < ActiveRecord::Base
2
- include Repia::UUIDModel
2
+ include Repia::Support::UUIDModel
3
3
  end
4
4
 
@@ -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.2.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-19 00:00:00.000000000 Z
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/base_controller.rb
96
- - lib/repia/base_helper.rb
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/uuid_model.rb
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/dummy/app/assets/javascripts/application.js
179
- - test/dummy/app/assets/javascripts/dummies.js
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/controllers/application_controller.rb
183
- - test/dummy/app/helpers/application_helper.rb
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/models/unique_model.rb
186
- - test/dummy/app/views/layouts/application.html.erb
187
- - test/dummy/bin/bundle
188
- - test/dummy/bin/rails
189
- - test/dummy/bin/rake
190
- - test/dummy/bin/setup
191
- - test/dummy/config/application.rb
192
- - test/dummy/config/boot.rb
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/locales/en.yml
207
- - test/dummy/config/routes.rb
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.ru
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/db/test.sqlite3
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/repia_base_controller_test.rb
225
- - test/repia_middlewares_test.rb
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/repia_unique_model_test.rb
228
- - test/test_helper.rb
229
+ - test/repia_middlewares_test.rb
230
+ - test/repia_base_controller_test.rb