From b09ebc5bbc7ea073da5644e582a4dd7ded351dfc Mon Sep 17 00:00:00 2001 From: Dmitry Babenko Date: Sat, 17 Aug 2019 18:49:21 +0300 Subject: [PATCH] API Resource generator --- README.md | 1 + .../auxiliary_rails/api_resource_generator.rb | 63 +++++++++++++++++ .../templates/apis/api_entity_template.rb.erb | 7 ++ .../templates/apis/api_helper_template.rb.erb | 5 ++ .../apis/api_resource_spec_template.rb.erb | 32 +++++++++ .../apis/api_resource_template.rb.erb | 70 +++++++++++++++++++ 6 files changed, 178 insertions(+) create mode 100644 lib/generators/auxiliary_rails/api_resource_generator.rb create mode 100644 lib/generators/auxiliary_rails/templates/apis/api_entity_template.rb.erb create mode 100644 lib/generators/auxiliary_rails/templates/apis/api_helper_template.rb.erb create mode 100644 lib/generators/auxiliary_rails/templates/apis/api_resource_spec_template.rb.erb create mode 100644 lib/generators/auxiliary_rails/templates/apis/api_resource_template.rb.erb diff --git a/README.md b/README.md index ee8e576..06f2ca9 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ rails new APP_PATH --skip-action-cable --skip-coffee --skip-test --database=post ### Generators ```sh +rails generate auxiliary_rails:api_resource rails generate auxiliary_rails:install_errors rails generate auxiliary_rails:install_rubocop rails generate auxiliary_rails:install_rubocop --no-specify-gems diff --git a/lib/generators/auxiliary_rails/api_resource_generator.rb b/lib/generators/auxiliary_rails/api_resource_generator.rb new file mode 100644 index 0000000..439ab64 --- /dev/null +++ b/lib/generators/auxiliary_rails/api_resource_generator.rb @@ -0,0 +1,63 @@ +require 'rails' + +module AuxiliaryRails + class ApiResourceGenerator < ::Rails::Generators::NamedBase + desc 'Stubs out a new API resource including an empty entity and spec.' + + class_option :api_module, + type: :string, + default: 'app', + desc: 'API module name' + class_option :api_version, + type: :numeric, + default: 1, + desc: 'API version' + class_option :skip_helper, + type: :boolean, + default: true, + desc: 'Indicates if helper generation needs to be skipped' + source_root File.expand_path('templates/apis', __dir__) + + def create_api_resource_file + template 'api_resource_template.rb.erb', + "app/#{api_module_path}/resources/#{plural_file_name}_resource.rb" + end + + def create_api_entity_file + template 'api_entity_template.rb.erb', + "app/#{api_module_path}/entities/#{file_name}_entity.rb" + end + + def create_api_helper_file + return if options[:skip_helper] + + template 'api_helper_template.rb.erb', + "app/#{api_module_path}/helpers/#{plural_file_name}_api_helper.rb" + end + + def create_api_resource_spec_file + template 'api_resource_spec_template.rb.erb', + "spec/#{api_module_path}/#{plural_file_name}_resource_spec.rb" + end + + private + + def api_module_name + "#{options[:api_module].camelize}V#{options[:api_version]}API" + end + + def api_module_path + "apis/#{options[:api_module]}_v#{options[:api_version]}_api" + end + + def api_url_path + api_name = 'api' + api_name += "-#{options[:api_module]}" if options[:api_module] != 'app' + "/#{api_name}/v#{options[:api_version]}/#{plural_name}" + end + + def entity_class_name + "#{api_module_name}::Entities::#{class_name}Entity" + end + end +end diff --git a/lib/generators/auxiliary_rails/templates/apis/api_entity_template.rb.erb b/lib/generators/auxiliary_rails/templates/apis/api_entity_template.rb.erb new file mode 100644 index 0000000..abc349f --- /dev/null +++ b/lib/generators/auxiliary_rails/templates/apis/api_entity_template.rb.erb @@ -0,0 +1,7 @@ +module <%= api_module_name %>::Entities + class <%= class_name %>Entity < Grape::Entity + expose :id + # TODO: define `<%= class_name %>Entity` exposes + expose :created_at, :updated_at + end +end diff --git a/lib/generators/auxiliary_rails/templates/apis/api_helper_template.rb.erb b/lib/generators/auxiliary_rails/templates/apis/api_helper_template.rb.erb new file mode 100644 index 0000000..4dfd666 --- /dev/null +++ b/lib/generators/auxiliary_rails/templates/apis/api_helper_template.rb.erb @@ -0,0 +1,5 @@ +module <%= api_module_name %>::Helpers + module <%= plural_name.camelize %>APIHelper + # TODO: define methods for `<%= plural_name.camelize %>Helper` + end +end diff --git a/lib/generators/auxiliary_rails/templates/apis/api_resource_spec_template.rb.erb b/lib/generators/auxiliary_rails/templates/apis/api_resource_spec_template.rb.erb new file mode 100644 index 0000000..5da4f19 --- /dev/null +++ b/lib/generators/auxiliary_rails/templates/apis/api_resource_spec_template.rb.erb @@ -0,0 +1,32 @@ +require 'rails_helper' + +RSpec.describe <%= api_module_name %>::Resources::<%= plural_name.camelize %>Resource, type: :request do + describe 'GET <%= api_url_path %>' do + subject { get '<%= api_url_path %>' } + + # TODO: write some tests + skip + end + + describe 'POST <%= api_url_path %>' do + subject { post '<%= api_url_path %>' } + + # TODO: write some tests + skip + end + + describe 'GET <%= api_url_path %>/:id' do + # TODO: write some tests + skip + end + + describe 'PUT <%= api_url_path %>/:id' do + # TODO: write some tests + skip + end + + describe 'DELETE <%= api_url_path %>/:id' do + # TODO: write some tests + skip + end +end diff --git a/lib/generators/auxiliary_rails/templates/apis/api_resource_template.rb.erb b/lib/generators/auxiliary_rails/templates/apis/api_resource_template.rb.erb new file mode 100644 index 0000000..fd23aeb --- /dev/null +++ b/lib/generators/auxiliary_rails/templates/apis/api_resource_template.rb.erb @@ -0,0 +1,70 @@ +module <%= api_module_name %>::Resources + class <%= plural_name.camelize %>Resource < Grape::API + helpers do + def collection + # TODO: add `policy_scope`? + @<%= plural_name %> ||= <%= class_name %>.all + end + + def resource + @<%= singular_name %> ||= <%= class_name %>.find(params[:id]) + end + end + + resource :<%= plural_name %> do + desc 'Returns resource collection' + get do + # TODO: authorize resource, :index? + present collection, + with: <%= entity_class_name %> + end + + desc 'Creates a <%= class_name %>' + params do + requires :<%= singular_name %>, type: Hash do + # TODO: define resource params or remove `params` block + end + end + post do + @<%= singular_name %> = <%= class_name %>.new(declared(params)[:<%= singular_name %>]) + # TODO: authorize resource, :create? + resource.save! + present resource, + with: <%= entity_class_name %> + end + + params do + requires :id, type: Integer, desc: '<%= class_name %> ID' + end + route_param :id do + desc 'Returns a <%= class_name %>' + get do + # TODO: authorize resource, :show? + present resource, + with: <%= entity_class_name %> + end + + desc 'Updates a <%= class_name %>' + params do + requires :<%= singular_name %>, type: Hash do + # TODO: define resource params or remove `params` block + end + end + put do + resource.assign_attributes(declared(params)[:<%= singular_name %>]) + # TODO: authorize resource, :update? + resource.save! + present resource, + with: <%= entity_class_name %> + end + + desc 'Deletes a <%= class_name %>' + delete do + # TODO: authorize resource, :destroy? + resource.destroy! + body false + end + end + end + end +end