From 4ee90f6c099738e275a8e9e8b41b63f3bac27380 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 3 Dec 2022 11:43:56 -0800 Subject: [PATCH] Add new errors and fix handling in ApiController --- app/controllers/api/v1/api_controller.rb | 118 ++++++++++-------- app/errors/api/v1/IncompatibleSkillError.rb | 29 +++++ app/errors/api/v1/NoJobProvidedError.rb | 38 +++--- app/errors/api/v1/NoJobSkillProvidedError.rb | 22 ++++ app/errors/api/v1/TooManySkillsOfTypeError.rb | 2 +- 5 files changed, 134 insertions(+), 75 deletions(-) create mode 100644 app/errors/api/v1/IncompatibleSkillError.rb create mode 100644 app/errors/api/v1/NoJobSkillProvidedError.rb diff --git a/app/controllers/api/v1/api_controller.rb b/app/controllers/api/v1/api_controller.rb index a019f99..1460919 100644 --- a/app/controllers/api/v1/api_controller.rb +++ b/app/controllers/api/v1/api_controller.rb @@ -1,68 +1,76 @@ module Api::V1 - class ApiController < ActionController::API + class ApiController < ActionController::API ##### Doorkeeper - include Doorkeeper::Rails::Helpers + include Doorkeeper::Rails::Helpers ##### Errors - rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotDestroyed, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response - rescue_from ActiveRecord::RecordNotSaved, with: :render_unprocessable_entity_response - rescue_from ActiveRecord::RecordNotUnique, with: :render_unprocessable_entity_response - rescue_from Api::V1::SameFavoriteUserError, with: :render_unprocessable_entity_response - rescue_from Api::V1::FavoriteAlreadyExistsError, with: :render_unprocessable_entity_response - rescue_from Api::V1::NoJobProvidedError, with: :render_unprocessable_entity_response - rescue_from Api::V1::TooManySkillsOfTypeError, with: :render_unprocessable_entity_response - rescue_from Api::V1::UnauthorizedError, with: :render_unauthorized_response - rescue_from ActionController::ParameterMissing, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotDestroyed, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response + rescue_from ActiveRecord::RecordNotSaved, with: :render_unprocessable_entity_response + rescue_from ActiveRecord::RecordNotUnique, with: :render_unprocessable_entity_response + rescue_from Api::V1::SameFavoriteUserError, with: :render_unprocessable_entity_response + rescue_from Api::V1::FavoriteAlreadyExistsError, with: :render_unprocessable_entity_response + rescue_from Api::V1::NoJobProvidedError, with: :render_unprocessable_entity_response + rescue_from Api::V1::TooManySkillsOfTypeError, with: :render_unprocessable_entity_response + rescue_from Api::V1::UnauthorizedError, with: :render_unauthorized_response + rescue_from ActionController::ParameterMissing, with: :render_unprocessable_entity_response + + rescue_from StandardError do |e| + render_error(e) + end ##### Hooks - before_action :current_user - before_action :set_default_content_type + before_action :current_user + before_action :set_default_content_type ##### Responders - respond_to :json + respond_to :json ##### Methods - # Assign the current user if the Doorkeeper token isn't nil, then - # update the current user's last seen datetime and last IP address - # before returning - def current_user - @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token + # Assign the current user if the Doorkeeper token isn't nil, then + # update the current user's last seen datetime and last IP address + # before returning + def current_user + @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token - return @current_user - end - - # Set the response content-type - def set_content_type(content_type) - response.headers["Content-Type"] = content_type - end - - # Set the default response content-type to application/javascript - # with a UTF-8 charset - def set_default_content_type - set_content_type("application/javascript; charset=utf-8") - end - - ### Error response methods - def render_unprocessable_entity_response(exception) - @exception = exception - render action: 'errors', status: :unprocessable_entity - end - - def render_not_found_response - response = { errors: [{ message: "Record could not be found.", code: "not_found" }]} - render 'not_found', status: :not_found - end - - def render_unauthorized_response - render action: 'errors', status: :unauthorized - end - - private - - def restrict_access - raise UnauthorizedError unless current_user - end + return @current_user end + + # Set the response content-type + def set_content_type(content_type) + response.headers["Content-Type"] = content_type + end + + # Set the default response content-type to application/javascript + # with a UTF-8 charset + def set_default_content_type + set_content_type("application/javascript; charset=utf-8") + end + + ### Error response methods + def render_error(error) + render action: 'errors', json: error.to_hash, status: error.http_status + end + + def render_unprocessable_entity_response(exception) + @exception = exception + render action: 'errors', status: :unprocessable_entity + end + + def render_not_found_response + response = { errors: [{ message: "Record could not be found.", code: "not_found" }] } + render 'not_found', status: :not_found + end + + def render_unauthorized_response + render action: 'errors', status: :unauthorized + end + + private + + def restrict_access + raise UnauthorizedError unless current_user + end + end end diff --git a/app/errors/api/v1/IncompatibleSkillError.rb b/app/errors/api/v1/IncompatibleSkillError.rb new file mode 100644 index 0000000..bd018d2 --- /dev/null +++ b/app/errors/api/v1/IncompatibleSkillError.rb @@ -0,0 +1,29 @@ +module Api::V1 + class IncompatibleSkillError < StandardError + def initialize(data) + @data = data + end + + def http_status + 422 + end + + def code + 'incompatible_skill' + end + + def message + 'The selected skill cannot be added to the current job' + end + + def to_hash + ap @data + { + message: message, + code: code, + job: @data[:job], + skill: @data[:skill] + } + end + end +end diff --git a/app/errors/api/v1/NoJobProvidedError.rb b/app/errors/api/v1/NoJobProvidedError.rb index 6727873..1e94592 100644 --- a/app/errors/api/v1/NoJobProvidedError.rb +++ b/app/errors/api/v1/NoJobProvidedError.rb @@ -1,22 +1,22 @@ module Api::V1 - class NoJobProvidedError < StandardError - def http_status - 422 - end - - def code - "no_job_provided" - end - - def message - "A job ID must be provided to search for job skills" - end - - def to_hash - { - message: message, - code: code - } - end + class NoJobProvidedError < StandardError + def http_status + 422 end + + def code + "no_job_provided" + end + + def message + "A job ID must be provided" + end + + def to_hash + { + message: message, + code: code + } + end + end end diff --git a/app/errors/api/v1/NoJobSkillProvidedError.rb b/app/errors/api/v1/NoJobSkillProvidedError.rb new file mode 100644 index 0000000..1e66e2d --- /dev/null +++ b/app/errors/api/v1/NoJobSkillProvidedError.rb @@ -0,0 +1,22 @@ +module Api::V1 + class NoJobSkillProvidedError < StandardError + def http_status + 422 + end + + def code + "no_job_skill_provided" + end + + def message + "A job skill ID must be provided" + end + + def to_hash + { + message: message, + code: code + } + end + end +end diff --git a/app/errors/api/v1/TooManySkillsOfTypeError.rb b/app/errors/api/v1/TooManySkillsOfTypeError.rb index 873a452..2323192 100644 --- a/app/errors/api/v1/TooManySkillsOfTypeError.rb +++ b/app/errors/api/v1/TooManySkillsOfTypeError.rb @@ -23,7 +23,7 @@ module Api { message: message, code: code, - idea_id: @data[:skill_type] + skill_type: @data[:skill_type] } end end