service_template 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +23 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGELOG.md +64 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +24 -0
  8. data/README.md +217 -0
  9. data/Rakefile +9 -0
  10. data/bin/service_template +5 -0
  11. data/lib/service_template.rb +55 -0
  12. data/lib/service_template/active_record_extensions/notifications_subscriber.rb +17 -0
  13. data/lib/service_template/active_record_extensions/seeder.rb +14 -0
  14. data/lib/service_template/active_record_extensions/stats.rb +37 -0
  15. data/lib/service_template/authentication.rb +8 -0
  16. data/lib/service_template/cli.rb +111 -0
  17. data/lib/service_template/deploy.rb +98 -0
  18. data/lib/service_template/gem_dependency.rb +37 -0
  19. data/lib/service_template/generators.rb +3 -0
  20. data/lib/service_template/generators/api_generator.rb +30 -0
  21. data/lib/service_template/generators/readme_generator.rb +47 -0
  22. data/lib/service_template/generators/scaffold_generator.rb +29 -0
  23. data/lib/service_template/generators/templates/api/app/apis/%name_tableize%_api.rb.tt +40 -0
  24. data/lib/service_template/generators/templates/api/app/models/%name_underscore%.rb.tt +2 -0
  25. data/lib/service_template/generators/templates/api/app/representers/%name_underscore%_representer.rb.tt +4 -0
  26. data/lib/service_template/generators/templates/api/spec/apis/%name_tableize%_api_spec.rb.tt +16 -0
  27. data/lib/service_template/generators/templates/api/spec/models/%name_underscore%_spec.rb.tt +9 -0
  28. data/lib/service_template/generators/templates/readme/README.md.tt +55 -0
  29. data/lib/service_template/generators/templates/readme/spec/docs/readme_spec.rb +7 -0
  30. data/lib/service_template/generators/templates/scaffold/.env.development.tt +9 -0
  31. data/lib/service_template/generators/templates/scaffold/.env.test.tt +10 -0
  32. data/lib/service_template/generators/templates/scaffold/.gitignore.tt +13 -0
  33. data/lib/service_template/generators/templates/scaffold/.rubocop.yml +24 -0
  34. data/lib/service_template/generators/templates/scaffold/.ruby-version.tt +1 -0
  35. data/lib/service_template/generators/templates/scaffold/Gemfile.tt +29 -0
  36. data/lib/service_template/generators/templates/scaffold/README.md +3 -0
  37. data/lib/service_template/generators/templates/scaffold/Rakefile +21 -0
  38. data/lib/service_template/generators/templates/scaffold/app.rb +19 -0
  39. data/lib/service_template/generators/templates/scaffold/app/apis/application_api.rb +9 -0
  40. data/lib/service_template/generators/templates/scaffold/app/apis/hello_api.rb.tt +10 -0
  41. data/lib/service_template/generators/templates/scaffold/config.ru.tt +21 -0
  42. data/lib/service_template/generators/templates/scaffold/config/database.yml.tt +19 -0
  43. data/lib/service_template/generators/templates/scaffold/config/initializers/active_record.rb +5 -0
  44. data/lib/service_template/generators/templates/scaffold/db/schema.rb +11 -0
  45. data/lib/service_template/generators/templates/scaffold/lib/.keep +0 -0
  46. data/lib/service_template/generators/templates/scaffold/log/.keep +0 -0
  47. data/lib/service_template/generators/templates/scaffold/spec/apis/hello_api_spec.rb.tt +17 -0
  48. data/lib/service_template/generators/templates/scaffold/spec/factories/.gitkeep +0 -0
  49. data/lib/service_template/generators/templates/scaffold/spec/spec_helper.rb +47 -0
  50. data/lib/service_template/grape_extenders.rb +30 -0
  51. data/lib/service_template/grape_extensions/error_formatter.rb +18 -0
  52. data/lib/service_template/grape_extensions/grape_helpers.rb +27 -0
  53. data/lib/service_template/identity.rb +45 -0
  54. data/lib/service_template/json_error.rb +24 -0
  55. data/lib/service_template/logger/log_transaction.rb +17 -0
  56. data/lib/service_template/logger/logger.rb +42 -0
  57. data/lib/service_template/logger/parseable.rb +37 -0
  58. data/lib/service_template/middleware/app_monitor.rb +17 -0
  59. data/lib/service_template/middleware/authentication.rb +32 -0
  60. data/lib/service_template/middleware/database_stats.rb +15 -0
  61. data/lib/service_template/middleware/logger.rb +67 -0
  62. data/lib/service_template/middleware/request_stats.rb +42 -0
  63. data/lib/service_template/output_formatters/entity.rb +15 -0
  64. data/lib/service_template/output_formatters/include_nil.rb +16 -0
  65. data/lib/service_template/output_formatters/json_api_representer.rb +9 -0
  66. data/lib/service_template/param_sanitizer.rb +30 -0
  67. data/lib/service_template/rspec_extensions/response_helpers.rb +46 -0
  68. data/lib/service_template/setup.rb +36 -0
  69. data/lib/service_template/sortable_api.rb +17 -0
  70. data/lib/service_template/stats.rb +43 -0
  71. data/lib/service_template/stats_d_timer.rb +26 -0
  72. data/lib/service_template/version.rb +45 -0
  73. data/lib/tasks/deploy.rake +11 -0
  74. data/lib/tasks/routes.rake +11 -0
  75. data/service_template.gemspec +42 -0
  76. data/spec/active_record_extensions/filter_by_hash_spec.rb +23 -0
  77. data/spec/active_record_extensions/seeder_spec.rb +13 -0
  78. data/spec/authentication_spec.rb +17 -0
  79. data/spec/deprecations/application_api_spec.rb +19 -0
  80. data/spec/deprecations/entity_spec.rb +9 -0
  81. data/spec/deprecations/filter_by_hash_spec.rb +9 -0
  82. data/spec/deprecations/napa_setup_spec.rb +52 -0
  83. data/spec/generators/api_generator_spec.rb +63 -0
  84. data/spec/generators/migration_generator_spec.rb +105 -0
  85. data/spec/generators/readme_generator_spec.rb +35 -0
  86. data/spec/generators/scaffold_generator_spec.rb +90 -0
  87. data/spec/grape_extenders_spec.rb +50 -0
  88. data/spec/grape_extensions/error_formatter_spec.rb +29 -0
  89. data/spec/grape_extensions/include_nil_spec.rb +23 -0
  90. data/spec/identity_spec.rb +50 -0
  91. data/spec/json_error_spec.rb +33 -0
  92. data/spec/logger/log_transaction_spec.rb +34 -0
  93. data/spec/logger/logger_spec.rb +14 -0
  94. data/spec/logger/parseable_spec.rb +16 -0
  95. data/spec/middleware/authentication_spec.rb +54 -0
  96. data/spec/middleware/database_stats_spec.rb +64 -0
  97. data/spec/middleware/request_stats_spec.rb +21 -0
  98. data/spec/sortable_api_spec.rb +56 -0
  99. data/spec/spec_helper.rb +45 -0
  100. data/spec/stats_d_timer_spec.rb +23 -0
  101. data/spec/stats_spec.rb +66 -0
  102. data/spec/version_spec.rb +40 -0
  103. data/tasks/spec.rake +9 -0
  104. data/tasks/version.rake +51 -0
  105. metadata +456 -0
@@ -0,0 +1,2 @@
1
+ class <%= name.classify %> < ActiveRecord::Base
2
+ end
@@ -0,0 +1,4 @@
1
+ class <%= name.classify %>Representer < ServiceTemplate::Representer
2
+ property :id, type: String
3
+
4
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ def app
4
+ ApplicationApi
5
+ end
6
+
7
+ describe <%= name.classify.pluralize %>Api do
8
+ include Rack::Test::Methods
9
+
10
+ describe 'e.g. GET, POST, PUT, etc.' do
11
+ it 'needs tests to be written!' do
12
+ pending('write tests for <%= name.classify.pluralize %>Api!')
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= name.classify %> do
4
+
5
+ it 'needs tests to be written!' do
6
+ pending('write tests for <%= name.classify %>!')
7
+ end
8
+
9
+ end
@@ -0,0 +1,55 @@
1
+ # <%= service_name %>
2
+
3
+ :bow: Please put your auspicious [Travis status button](http://docs.travis-ci.com/user/status-images/) here :bow:
4
+
5
+ 1. [Overview](#overview)
6
+ 2. [How Does It Work](#how-does-it-work)
7
+ 3. [Endpoints](#endpoints)
8
+ 4. [Development](#development)
9
+ 5. [Extra Links](#extra-links)
10
+
11
+ ### Overview
12
+
13
+ :bow: Tell us about your wonderful service :bow:
14
+
15
+ In this section, please answer the questions, "What is this service?" or "What does this service do?"
16
+
17
+ ### How Does It Work
18
+
19
+ Ohhh tell us, how does it function? :bow: :bow:
20
+
21
+ Tell us about the __mechanics__ or __logic__ driving the service. Diagrams and pictures are :angel:
22
+
23
+ ### Endpoints
24
+
25
+ How must we interact with your great service? :bow:
26
+
27
+ Try typing `rake routes` into your console, and then paste that here.
28
+
29
+ If those endpoints need to be explained in more detail, please bless us with your wisdom.
30
+
31
+ ### Development
32
+
33
+ ```
34
+ bundle install
35
+
36
+ rake db:reset
37
+
38
+ rspec spec
39
+
40
+ rackup
41
+ ```
42
+
43
+ So wonderful, so informative! :bow:
44
+
45
+ What else do we need to know so that a new developer can start contributing __within 30 minutes__?
46
+
47
+ ### Extra Links
48
+
49
+ What a perfectly constructed service! We're so honored :bow:
50
+
51
+ If your service makes heavy use of other gems or API's, imbue us with that knowledge in the form of
52
+
53
+ - [Link to documentation]()
54
+ - [etc.]()
55
+ - [For information on how to create links in Markdown, please click here](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#links)
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'README' do
4
+ it 'has been filled out' do
5
+ pending 'Please fill out the sections that have a :bow:'
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # Uncomment when using ServiceTemplate::Middleware::Authentication
2
+ # HEADER_PASSWORD=''
3
+
4
+ SERVICE_NAME=<%= app_name %>
5
+
6
+ DATABASE_USER='<%= @database_user %>'
7
+ DATABASE_PASSWORD=''
8
+ DATABASE_HOST=localhost
9
+ DATABASE_NAME=<%= app_name.underscore %>_development
@@ -0,0 +1,10 @@
1
+ # Uncomment when using ServiceTemplate::Middleware::Authentication
2
+ # HEADER_PASSWORD=''
3
+
4
+ SERVICE_NAME=<%= app_name %>
5
+ RACK_ENV=test
6
+
7
+ DATABASE_USER='<%= @database_user %>'
8
+ DATABASE_PASSWORD=''
9
+ DATABASE_HOST=localhost
10
+ DATABASE_NAME=<%= app_name.underscore %>_test
@@ -0,0 +1,13 @@
1
+ .DS_Store
2
+ .env
3
+ .vagrant
4
+ .rspec
5
+ .env
6
+ !.env.test
7
+ !log/.keep
8
+ log/*
9
+ tmp/*
10
+ coverage
11
+ !.keep
12
+ .ruby-gemset
13
+ .ruby-version
@@ -0,0 +1,24 @@
1
+ Documentation:
2
+ Enabled: false
3
+
4
+ Encoding:
5
+ EnforcedStyle: when_needed
6
+
7
+ LineLength:
8
+ Max: 120
9
+
10
+ # This cop checks for big numeric literals without _ between groups of digits in them.
11
+ # ie: 100_000 vs 100000
12
+ NumericLiterals:
13
+ Enabled: false
14
+
15
+ # how to bubble up exceptions (raise or fail)
16
+ SignalException:
17
+ EnforcedStyle: only_raise
18
+
19
+ MethodLength:
20
+ Max: 30
21
+
22
+ AllCops:
23
+ Exclude:
24
+ - db/schema.rb
@@ -0,0 +1,29 @@
1
+ source 'https://rubygems.org'
2
+ ruby "2.1.5"
3
+
4
+ gem 'rack-cors'
5
+ gem '<%= @database_gem %>'
6
+ gem 'activerecord', '~> 4.2.0', :require => 'active_record'
7
+ gem 'json'
8
+ gem 'service_template'
9
+ gem 'roar'
10
+ gem 'grape-swagger'
11
+ gem 'grape-activerecord'
12
+
13
+ group :development,:test do
14
+ gem 'pry'
15
+ end
16
+
17
+ group :development do
18
+ gem 'rubocop', require: false
19
+ gem 'shotgun', require: false
20
+ end
21
+
22
+ group :test do
23
+ gem 'factory_girl'
24
+ gem 'rspec'
25
+ gem 'rack-test'
26
+ gem 'simplecov'
27
+ gem 'webmock'
28
+ gem 'database_cleaner'
29
+ end
@@ -0,0 +1,3 @@
1
+ # Welcome to ServiceTemplate
2
+
3
+ TODO: Add an awesome README that explains how all this stuff works!
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/setup'
3
+ require 'service_template/setup'
4
+ require 'dotenv'
5
+ require 'grape/activerecord/rake'
6
+ ServiceTemplate.load_environment
7
+
8
+ require './app'
9
+ require 'json'
10
+
11
+ # active record tasks
12
+ namespace :db do
13
+ # Some db tasks require your app code to be loaded
14
+ task :environment do
15
+ require_relative 'app'
16
+ end
17
+ end
18
+
19
+ Dir.glob('./lib/tasks/*.rake').each { |r| import r }
20
+
21
+
@@ -0,0 +1,19 @@
1
+ # load bundler
2
+ require 'bundler/setup'
3
+ Bundler.setup(:default)
4
+ require 'service_template/setup'
5
+ Bundler.require(:default, ServiceTemplate.env.to_sym)
6
+ require 'service_template'
7
+
8
+ # load environment
9
+ ServiceTemplate.load_environment
10
+
11
+ # autoload initalizers
12
+ Dir['./config/initializers/**/*.rb'].map { |file| require file }
13
+
14
+ # load middleware configs
15
+ Dir['./config/middleware/**/*.rb'].map { |file| require file }
16
+
17
+ # autoload app
18
+ relative_load_paths = %w(app/apis app/representers app/models app/workers lib)
19
+ ActiveSupport::Dependencies.autoload_paths += relative_load_paths
@@ -0,0 +1,9 @@
1
+ class ApplicationApi < Grape::API
2
+ format :json
3
+ extend ServiceTemplate::GrapeExtenders
4
+
5
+ mount HelloApi => '/'
6
+
7
+ add_swagger_documentation
8
+ end
9
+
@@ -0,0 +1,10 @@
1
+ class HelloApi < Grape::API
2
+
3
+ resource :hello do
4
+ desc 'Return a Hello World message'
5
+ get do
6
+ { message: 'Hello Wonderful World, from <%= app_name.classify %>!' }
7
+ end
8
+ end
9
+
10
+ end
@@ -0,0 +1,21 @@
1
+ require './app'
2
+
3
+ # Experimental StatsD Emitter for ActiveRecord
4
+ # require 'service_template/active_record_extensions/stats.rb'
5
+
6
+ # use Rack::Cors do
7
+ # allow do
8
+ # origins '*'
9
+ # resource '*', headers: :any, methods: [:get, :post, :delete, :put, :options]
10
+ # end
11
+ # end
12
+ #
13
+ # use Honeybadger::Rack::ErrorNotifier
14
+ # use ServiceTemplate::Middleware::Logger
15
+
16
+ use ServiceTemplate::Middleware::AppMonitor
17
+ # Uncomment to require header passwords for all requests
18
+ # use ServiceTemplate::Middleware::Authentication
19
+ use ActiveRecord::ConnectionAdapters::ConnectionManagement
20
+
21
+ run ApplicationApi
@@ -0,0 +1,19 @@
1
+ defaults: &defaults
2
+ encoding: <%= @database_encoding %>
3
+ adapter: <%= @database_adapter %>
4
+ host: <%%= ENV['DATABASE_HOST'] %>
5
+ username: <%%= ENV['DATABASE_USER'] %>
6
+ password: <%%= ENV['DATABASE_PASSWORD'] %>
7
+ database: <%%= ENV['DATABASE_NAME'] %>
8
+
9
+ production:
10
+ <<: *defaults
11
+
12
+ development:
13
+ <<: *defaults
14
+
15
+ test:
16
+ <<: *defaults
17
+
18
+ staging:
19
+ <<: *defaults
@@ -0,0 +1,5 @@
1
+ require 'erb'
2
+ db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[ServiceTemplate.env]
3
+ ActiveRecord::Base.establish_connection(db)
4
+ ActiveRecord::Base.logger = ServiceTemplate::Logger.logger if ServiceTemplate.env.development?
5
+ ActiveRecord::Base.include_root_in_json = false
@@ -0,0 +1,11 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your
6
+ # database schema. If you need to create the application database on another
7
+ # system, you should be using db:schema:load, not running all the migrations
8
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ def app
4
+ ApplicationApi
5
+ end
6
+
7
+ describe HelloApi do
8
+ include Rack::Test::Methods
9
+
10
+ describe 'GET /hello' do
11
+ it 'returns a hello world message' do
12
+ get '/hello'
13
+ expect(response_body).to eq({ message: 'Hello Wonderful World, from <%= app_name.classify %>!' }.to_json)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,47 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'webmock/rspec'
4
+ require 'rack/test'
5
+ require 'simplecov'
6
+ require 'factory_girl'
7
+ require 'service_template/rspec_extensions/response_helpers'
8
+
9
+ FactoryGirl.definition_file_paths = %w(./spec/factories)
10
+ FactoryGirl.find_definitions
11
+ SimpleCov.start do
12
+ add_filter "/spec\/.*/"
13
+ add_filter "/vendor\/.*/"
14
+ end
15
+
16
+ require './app'
17
+ require 'database_cleaner'
18
+
19
+ SimpleCov.start do
20
+ add_filter "/spec\/.*/"
21
+ add_filter "/vendor\/.*/"
22
+ end
23
+
24
+ # fail once the test coverage gets below an accepted amount
25
+ # SimpleCov.minimum_coverage 90
26
+
27
+ # Requires supporting ruby files with custom matchers and macros, etc,
28
+ # in spec/support/ and its subdirectories.
29
+ Dir['./spec/support/**/*.rb'].each { |f| require f }
30
+
31
+ RSpec.configure do |config|
32
+ config.include FactoryGirl::Syntax::Methods
33
+ config.include ServiceTemplate::RspecExtensions::ResponseHelpers
34
+
35
+ config.before(:suite) do
36
+ DatabaseCleaner.strategy = :transaction
37
+ DatabaseCleaner.clean_with(:truncation)
38
+ end
39
+
40
+ config.before(:each) do
41
+ DatabaseCleaner.start
42
+ end
43
+
44
+ config.after(:each) do
45
+ DatabaseCleaner.clean
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ module ServiceTemplate
2
+ module GrapeExtenders
3
+ def self.extended(modified_class)
4
+ # when extended, set the exceptions to handle
5
+
6
+ # if AR is being used, rescue from common AR errors
7
+ if defined?(::ActiveRecord)
8
+ modified_class.rescue_from ::ActiveRecord::RecordNotFound do |e|
9
+ err = ServiceTemplate::JsonError.new(:record_not_found, 'record not found')
10
+ ServiceTemplate::Logger.logger.debug ServiceTemplate::Logger.response(404, {}, err)
11
+ rack_response(err.to_json, 404)
12
+ end
13
+ modified_class.rescue_from ::ActiveRecord::RecordInvalid do |e|
14
+ err = ServiceTemplate::JsonError.new(:unprocessable_entity, e.message, e.record.errors.messages)
15
+ ServiceTemplate::Logger.logger.debug ServiceTemplate::Logger.response(422, {}, err)
16
+ rack_response(err.to_json, 422)
17
+ end
18
+ end
19
+
20
+ # if AASM is being used, rescue from invalid transitions
21
+ if defined?(::AASM)
22
+ modified_class.rescue_from ::AASM::InvalidTransition do |e|
23
+ err = ServiceTemplate::JsonError.new(:unprocessable_entity, e.message)
24
+ ServiceTemplate::Logger.logger.debug ServiceTemplate::Logger.response(422, {}, err)
25
+ rack_response(err.to_json, 422)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ if defined?(Grape)
2
+ module Grape
3
+ module ErrorFormatter
4
+ module Json
5
+ class << self
6
+ def call(message, backtrace, options = {}, env = nil)
7
+ result = message.is_a?(ServiceTemplate::JsonError) ? message : ServiceTemplate::JsonError.new(:api_error, message)
8
+
9
+ if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
10
+ result = result.to_h.merge(backtrace: backtrace)
11
+ end
12
+ MultiJson.dump(result)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end