mini_api
Advanced tools
| # frozen_string_literal: true | ||
| module MiniApi | ||
| module Translation | ||
| # Module to handle the +message+ key on json response. | ||
| # Will identify if model has errors or not and define the I18n path to +notice+, for model without errors | ||
| # and +alert+ for model with errors. | ||
| # There is three possible path for messages: | ||
| # | ||
| # The path based on model name | ||
| # mini_api: | ||
| # messages: | ||
| # model_name: | ||
| # action_name: | ||
| # notitce: | ||
| # alert: | ||
| # | ||
| # The path based on controller name | ||
| # mini_api: | ||
| # messages: | ||
| # controller: | ||
| # controller_name: | ||
| # action_name: | ||
| # notitce: | ||
| # alert: | ||
| # | ||
| # And the last, is per action path: | ||
| # mini_api: | ||
| # messages: | ||
| # actions: | ||
| # create: | ||
| # notice: '%{resource_name} foi criado com sucesso.' | ||
| # alert: '%{resource_name} não pôde ser criado.' | ||
| module Message | ||
| def message | ||
| kind = @resource.errors.empty? ? 'notice' : 'alert' | ||
| I18n.t( | ||
| kind, | ||
| scope: model_message_path || controller_message_path || default_message_path, | ||
| resource_name: @resource.class.model_name.human, | ||
| default: '' | ||
| ) | ||
| end | ||
| private | ||
| def model_message_path | ||
| model_path = "mini_api.messages.#{@resource.model_name.i18n_key}.#{@controller.action_name}" | ||
| model_path if I18n.exists? model_path | ||
| end | ||
| def controller_message_path | ||
| controller_path = | ||
| "mini_api.messages.controller.#{@controller.controller_name}.#{@controller.action_name}" | ||
| controller_path if I18n.exists? controller_path | ||
| end | ||
| def default_message_path | ||
| ['mini_api', 'messages', 'actions', @controller.action_name].join('.') | ||
| end | ||
| end | ||
| end | ||
| end |
@@ -5,2 +5,3 @@ # frozen_string_literal: true | ||
| require 'mini_api/case_transform' | ||
| require 'mini_api/translation/message' | ||
@@ -11,2 +12,3 @@ module MiniApi | ||
| include Serialization | ||
| include Translation::Message | ||
@@ -22,3 +24,3 @@ def initialize(controller, resource, options = {}) | ||
| success: resource_has_errors? == false, | ||
| message: @options[:message] || default_message | ||
| message: @options[:message] || message | ||
| } | ||
@@ -33,6 +35,2 @@ | ||
| # This is for an problem with ActiveModelSerializer that adds an error | ||
| # attribute when resource is an ActiveModel instance | ||
| body[:data] = body[:data].except('errors') if body[:data]&.key?('errors') | ||
| body = CaseTransform.response_keys(body) | ||
@@ -69,24 +67,2 @@ | ||
| def default_message | ||
| kind = resource_has_errors? ? 'alert' : 'notice' | ||
| model_path = "mini_api.messages.#{@resource.model_name.i18n_key}" | ||
| if I18n.exists? model_path | ||
| I18n.t( | ||
| kind, | ||
| scope: "#{model_path}.#{@controller.action_name}", | ||
| resource_name: @resource.class.model_name.human, | ||
| default: '' | ||
| ) | ||
| else | ||
| I18n.t( | ||
| kind, | ||
| scope: [:mini_api, :messages, :actions, @controller.action_name], | ||
| resource_name: @resource.class.model_name.human, | ||
| default: '' | ||
| ) | ||
| end | ||
| end | ||
| def previously_new_record? | ||
@@ -93,0 +69,0 @@ return true if @resource.is_a?(ActiveRecord::Base) && @resource.previously_new_record? |
| # frozen_string_literal: true | ||
| require 'alba' | ||
| module MiniApi | ||
| # | ||
| # This module is responsible to handler integration with Active Model Serialier gem | ||
| # call the +get_serializer+ method of controller implemented by gem | ||
| # to find the serializer of informed object. | ||
| module Serialization | ||
| # This method search by serializer using the module parents of controller. | ||
| # With this, is possible define serializers for the same resource | ||
| # in different controller scopes | ||
| def serialiable_body(resource) | ||
| return resource unless defined?(ActiveModel::Serializer) | ||
| controller_scope = @controller.class.module_parents | ||
| @controller.get_serializer(resource) | ||
| resource_class = | ||
| if resource.respond_to?(:model) | ||
| resource.model | ||
| else | ||
| resource.class | ||
| end | ||
| serializer_class = | ||
| loop do | ||
| serializer_class = | ||
| "#{controller_scope.first}::#{resource_class}Resource".safe_constantize | ||
| break serializer_class if serializer_class | ||
| break DefaultResource if controller_scope.empty? | ||
| controller_scope.shift | ||
| end | ||
| serializer_class.new(resource) | ||
| end | ||
| # Search by the nested class +Error+ on serializer | ||
| # Follow the same steps for +get_serializer+ | ||
| def get_error_serializer(resource) | ||
| serializer_class = @controller.get_serializer(resource) | ||
| error_serializer = serialiable_body(resource) | ||
| "#{serializer_class.serializer}::Error".safe_constantize | ||
| return unless error_serializer | ||
| "#{error_serializer.class}::Error".safe_constantize | ||
| end | ||
| # Empty serializer class for when resource does not have a custom class | ||
| class DefaultResource | ||
| include Alba::Resource | ||
| end | ||
| end | ||
| end |
| # frozen_string_literal: true | ||
| module MiniApi | ||
| VERSION = '0.1.4' | ||
| VERSION = '0.1.5' | ||
| end |
+34
-18
|  | ||
| [](https://codeclimate.com/github/leoncruz/api-responder/maintainability) | ||
| [](https://codeclimate.com/github/leoncruz/api-responder/test_coverage) | ||
| [](https://codeclimate.com/github/leoncruz/mini_api/maintainability) | ||
| [](https://codeclimate.com/github/leoncruz/mini_api/test_coverage) | ||
@@ -11,2 +11,3 @@ # Mini Api | ||
| - [Respondering json](#respondering-json) | ||
| - [Data Serialization](#data-serialization) | ||
| - [Success and failure actions](#success-and-failure-actions) | ||
@@ -34,3 +35,2 @@ - [Errors](#errors) | ||
| You must install [Kaminari](https://github.com/kaminari/kaminari) to handle pagination | ||
| and [Active Model Serializers](http://github.com/rails-api/active_model_serializers) to handle data serialization | ||
@@ -97,2 +97,18 @@ ## Usage | ||
| ### Data Serialization | ||
| This gem is integrated to [Alba](https://github.com/okuramasafumi/Alba) to create your `resources`. A simple resource example: | ||
| ```ruby | ||
| class UserResource | ||
| include Alba::Resource | ||
| attributes :id, :name, :email | ||
| end | ||
| ``` | ||
| When the `render_json` methods receive an instance of `user` or a `ActiveRecord::Relation` of `users` will search by `UserResource`. | ||
| If you have a nested controller like: `Api::V1::UsersController`, `mini_api` will search by resources in controller namespace. | ||
| First will search per `Api::V1::UserResource`, after `Api::UserResource` and then `UserResource` until find. | ||
| That way, even if your `controller` and `resource` are defined in different namespace levels, `MiniApi` will find. | ||
| ### Success and failure actions | ||
@@ -151,16 +167,16 @@ | ||
| ### Errors | ||
| To show errors of a model, by default will use the `errors.messages` method, but `MiniApi` adds an ability to `active_model_serializers` to create a error serializer | ||
| as a nested class in your serializer. Example: | ||
| To show errors of a model, by default will use the `errors.messages` method, but `MiniApi` adds an ability to `Alba` to create a error resource | ||
| as a nested class in your resource. Example: | ||
| ```ruby | ||
| class UserSerializer < ActiveModel::Serializer | ||
| attributes :id, :first_name, :last_name | ||
| class UserResource | ||
| include Alba::Resource | ||
| class Error < ActiveModel::Serializer | ||
| attributes :user | ||
| attributes :id, :name, :email | ||
| def user | ||
| { | ||
| first_name: object.errors[:first_name], | ||
| last_name: object.errors[:last_name], | ||
| } | ||
| class Error | ||
| include Alba::Resource | ||
| attribute :user do | ||
| object.errors.full_messages | ||
| end | ||
@@ -175,6 +191,3 @@ end | ||
| "errors": { | ||
| "user": { | ||
| "first_name": "can't be blank", | ||
| "last_name": "can't be blank" | ||
| } | ||
| "user": ["First name can't be blank"] | ||
| }, | ||
@@ -196,2 +209,5 @@ "message": "User could not be created." | ||
| It is possible define a translation based on controller, useful if you use nested controlers. The path is: | ||
| `min_api.messages.controller_name.action_name.alert` | ||
| ### Transform keys | ||
@@ -198,0 +214,0 @@ |