stitches 4.0.2 → 4.2.0.RC3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +0 -38
- data/.gitignore +1 -0
- data/README.md +32 -4
- data/lib/stitches/add_disabled_at_to_api_clients_generator.rb +18 -0
- data/lib/stitches/allowlist_middleware.rb +20 -6
- data/lib/stitches/api_client_access_wrapper.rb +42 -11
- data/lib/stitches/api_key.rb +5 -5
- data/lib/stitches/configuration.rb +4 -0
- data/lib/stitches/generator_files/db/migrate/add_disabled_at_to_api_clients.rb +5 -0
- data/lib/stitches/generator_files/db/migrate/add_enabled_to_api_clients.rb +1 -5
- data/lib/stitches/generator_files/db/migrate/create_api_clients.rb +2 -5
- data/lib/stitches/generator_files/db/migrate/enable_uuid_ossp_extension.rb +1 -5
- data/lib/stitches/version.rb +1 -1
- data/lib/stitches_norailtie.rb +1 -0
- data/spec/api_key_middleware_spec.rb +368 -0
- data/spec/api_version_constraint_middleware_spec.rb +58 -0
- data/spec/configuration_spec.rb +1 -1
- data/spec/deprecation_spec.rb +1 -1
- data/spec/error_spec.rb +1 -1
- data/spec/errors_spec.rb +3 -3
- data/spec/fake_app/.rspec +1 -0
- data/spec/fake_app/.ruby-version +1 -0
- data/spec/fake_app/Gemfile +53 -0
- data/spec/fake_app/README.md +24 -0
- data/spec/fake_app/Rakefile +6 -0
- data/spec/fake_app/app/assets/config/manifest.js +2 -0
- data/spec/fake_app/app/assets/stylesheets/application.css +15 -0
- data/spec/fake_app/app/controllers/api.rb +2 -0
- data/spec/fake_app/app/controllers/api/api_controller.rb +31 -0
- data/spec/fake_app/app/controllers/api/v1.rb +2 -0
- data/spec/fake_app/app/controllers/api/v1/hellos_controller.rb +7 -0
- data/spec/fake_app/app/controllers/api/v1/pings_controller.rb +16 -0
- data/spec/fake_app/app/controllers/api/v2.rb +2 -0
- data/spec/fake_app/app/controllers/api/v2/hellos_controller.rb +7 -0
- data/spec/fake_app/app/controllers/api/v2/pings_controller.rb +16 -0
- data/spec/fake_app/app/controllers/application_controller.rb +2 -0
- data/spec/fake_app/app/helpers/application_helper.rb +2 -0
- data/spec/fake_app/app/models/api_client.rb +2 -0
- data/spec/fake_app/app/models/application_record.rb +3 -0
- data/spec/fake_app/bin/rails +4 -0
- data/spec/fake_app/bin/rake +4 -0
- data/spec/fake_app/bin/setup +33 -0
- data/spec/fake_app/config.ru +6 -0
- data/spec/fake_app/config/application.rb +35 -0
- data/spec/fake_app/config/boot.rb +3 -0
- data/spec/fake_app/config/credentials.yml.enc +1 -0
- data/spec/fake_app/config/database.yml +25 -0
- data/spec/fake_app/config/environment.rb +5 -0
- data/spec/fake_app/config/environments/development.rb +71 -0
- data/spec/fake_app/config/environments/production.rb +109 -0
- data/spec/fake_app/config/environments/test.rb +52 -0
- data/spec/fake_app/config/initializers/assets.rb +12 -0
- data/spec/fake_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/fake_app/config/initializers/filter_parameter_logging.rb +6 -0
- data/spec/fake_app/config/initializers/stitches.rb +24 -0
- data/spec/fake_app/config/locales/en.yml +33 -0
- data/spec/fake_app/config/master.key +1 -0
- data/spec/fake_app/config/puma.rb +43 -0
- data/spec/fake_app/config/routes.rb +17 -0
- data/spec/fake_app/config/storage.yml +34 -0
- data/spec/fake_app/db/development.sqlite3 +0 -0
- data/spec/fake_app/db/migrate/20210802153118_enable_uuid_ossp_extension.rb +7 -0
- data/spec/fake_app/db/migrate/20210802153119_create_api_clients.rb +14 -0
- data/spec/fake_app/db/schema_missing_disabled_at.rb +12 -0
- data/spec/fake_app/db/schema_missing_enabled.rb +11 -0
- data/spec/fake_app/db/schema_modern.rb +13 -0
- data/spec/fake_app/db/seeds.rb +7 -0
- data/spec/fake_app/db/test.sqlite3 +0 -0
- data/spec/fake_app/doc/api.md +4 -0
- data/spec/fake_app/lib/tasks/generate_api_key.rake +10 -0
- data/spec/fake_app/public/404.html +67 -0
- data/spec/fake_app/public/422.html +67 -0
- data/spec/fake_app/public/500.html +66 -0
- data/spec/fake_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/fake_app/public/apple-touch-icon.png +0 -0
- data/spec/fake_app/public/favicon.ico +0 -0
- data/spec/fake_app/public/javascripts/apitome/application.js +31 -0
- data/spec/fake_app/public/robots.txt +1 -0
- data/spec/fake_app/public/stylesheets/apitome/application.css +269 -0
- data/spec/fake_app/test/application_system_test_case.rb +5 -0
- data/spec/fake_app/test/test_helper.rb +13 -0
- data/spec/fake_app/tmp/development_secret.txt +1 -0
- data/spec/integration/add_to_rails_app_spec.rb +9 -1
- data/spec/rails_helper.rb +64 -0
- data/spec/valid_mime_type_middleware_spec.rb +59 -0
- data/spec/valid_mime_type_spec.rb +6 -4
- data/stitches.gemspec +2 -0
- metadata +167 -11
- data/spec/api_client_access_wrapper_spec.rb +0 -52
- data/spec/api_key_spec.rb +0 -208
- data/spec/api_version_constraint_spec.rb +0 -33
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
RSpec.describe "/api/hellos", type: :request do
|
5
|
+
let(:version) { 8 }
|
6
|
+
let(:accept_header) { "application/json; version=#{version}" }
|
7
|
+
let(:headers) {
|
8
|
+
h = {}
|
9
|
+
h["Accept"] = accept_header if accept_header
|
10
|
+
h
|
11
|
+
}
|
12
|
+
|
13
|
+
before do
|
14
|
+
Stitches.configuration.reset_to_defaults!
|
15
|
+
Stitches.configuration.allowlist_regexp = /.*hello.*/
|
16
|
+
Stitches::ApiClientAccessWrapper.clear_api_cache
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when correctly configured for version 1" do
|
20
|
+
let(:version) { 1 }
|
21
|
+
|
22
|
+
it "executes the correct controller" do
|
23
|
+
get "/api/hellos", headers: headers
|
24
|
+
|
25
|
+
expect(response.body).to include "Hello"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when correctly configured for version 2" do
|
30
|
+
let(:version) { 2 }
|
31
|
+
|
32
|
+
it "executes the correct controller" do
|
33
|
+
get "/api/hellos", headers: headers
|
34
|
+
|
35
|
+
expect(response.body).to include "Greetings"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when correctly configured for a version that does not exist" do
|
40
|
+
let(:version) { 6 }
|
41
|
+
|
42
|
+
it "fails to map to a controller" do
|
43
|
+
expect {
|
44
|
+
get "/api/hellos", headers: headers
|
45
|
+
}.to raise_error(ActionController::RoutingError)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when accept header is missing version" do
|
50
|
+
let(:accept_header) { "application/json" }
|
51
|
+
|
52
|
+
it "fails to map to a controller" do
|
53
|
+
expect {
|
54
|
+
get "/api/hellos", headers: headers
|
55
|
+
}.to raise_error(ActionController::RoutingError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/configuration_spec.rb
CHANGED
data/spec/deprecation_spec.rb
CHANGED
data/spec/error_spec.rb
CHANGED
data/spec/errors_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'rails_helper'
|
2
2
|
|
3
3
|
class MyFakeError < StandardError
|
4
4
|
end
|
@@ -10,9 +10,9 @@ class FakePersonHolder
|
|
10
10
|
validates_presence_of :name
|
11
11
|
|
12
12
|
def valid?
|
13
|
-
# doing this because we can't use validates_associated on a non-AR object, and
|
13
|
+
# doing this because we can't use validates_associated on a non-AR object, and
|
14
14
|
# our logic doesn't depend on validates_associated, per se
|
15
|
-
super.tap {
|
15
|
+
super.tap {
|
16
16
|
unless person.valid?
|
17
17
|
errors.add(:person,"is not valid")
|
18
18
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.7.3
|
@@ -0,0 +1,53 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
4
|
+
ruby '2.7.3'
|
5
|
+
|
6
|
+
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
|
7
|
+
gem 'rails', '~> 6.1.4'
|
8
|
+
# Use sqlite3 as the database for Active Record
|
9
|
+
gem 'sqlite3', '~> 1.4'
|
10
|
+
# Use Puma as the app server
|
11
|
+
gem 'puma', '~> 5.0'
|
12
|
+
# Use SCSS for stylesheets
|
13
|
+
gem 'sass-rails', '>= 6'
|
14
|
+
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
15
|
+
gem 'jbuilder', '~> 2.7'
|
16
|
+
# Use Active Model has_secure_password
|
17
|
+
# gem 'bcrypt', '~> 3.1.7'
|
18
|
+
|
19
|
+
# Use Active Storage variant
|
20
|
+
# gem 'image_processing', '~> 1.2'
|
21
|
+
|
22
|
+
gem 'stitches'
|
23
|
+
|
24
|
+
group :development, :test do
|
25
|
+
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
26
|
+
# gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
27
|
+
end
|
28
|
+
|
29
|
+
group :development do
|
30
|
+
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
|
31
|
+
gem 'web-console', '>= 4.1.0'
|
32
|
+
# Display performance information such as SQL time and flame graphs for each request in your browser.
|
33
|
+
# Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
|
34
|
+
gem 'rack-mini-profiler', '~> 2.0'
|
35
|
+
end
|
36
|
+
|
37
|
+
group :test do
|
38
|
+
# Adds support for Capybara system testing and selenium driver
|
39
|
+
gem 'capybara', '>= 3.26'
|
40
|
+
gem 'selenium-webdriver'
|
41
|
+
# Easy installation and use of web drivers to run system tests with browsers
|
42
|
+
gem 'webdrivers'
|
43
|
+
end
|
44
|
+
|
45
|
+
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
46
|
+
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|
47
|
+
gem 'apitome'
|
48
|
+
|
49
|
+
group :development, :test do
|
50
|
+
gem 'rspec'
|
51
|
+
gem 'rspec-rails'
|
52
|
+
gem 'rspec_api_documentation'
|
53
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# README
|
2
|
+
|
3
|
+
This README would normally document whatever steps are necessary to get the
|
4
|
+
application up and running.
|
5
|
+
|
6
|
+
Things you may want to cover:
|
7
|
+
|
8
|
+
* Ruby version
|
9
|
+
|
10
|
+
* System dependencies
|
11
|
+
|
12
|
+
* Configuration
|
13
|
+
|
14
|
+
* Database creation
|
15
|
+
|
16
|
+
* Database initialization
|
17
|
+
|
18
|
+
* How to run the test suite
|
19
|
+
|
20
|
+
* Services (job queues, cache servers, search engines, etc.)
|
21
|
+
|
22
|
+
* Deployment instructions
|
23
|
+
|
24
|
+
* ...
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
|
6
|
+
* vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Api::ApiController < ActionController::API
|
2
|
+
include Stitches::Deprecation
|
3
|
+
#
|
4
|
+
# The order of the rescue_from blocks is important - ActiveRecord::RecordNotFound must come after StandardError,
|
5
|
+
# otherwise ActiveRecord::RecordNotFound exceptions will get rescued in the StandardError block.
|
6
|
+
# See the documentation for rescue_from for further explanation:
|
7
|
+
# https://apidock.com/rails/ActiveSupport/Rescuable/ClassMethods/rescue_from
|
8
|
+
# Specifically, this part: "Handlers are inherited. They are searched from right to left, from bottom to top, and up
|
9
|
+
# the hierarchy."
|
10
|
+
#
|
11
|
+
rescue_from StandardError do |exception|
|
12
|
+
render json: { errors: Stitches::Errors.from_exception(exception) }, status: :internal_server_error
|
13
|
+
end
|
14
|
+
|
15
|
+
rescue_from ActiveRecord::RecordNotFound do |exception|
|
16
|
+
render json: { errors: Stitches::Errors.from_exception(exception) }, status: :not_found
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_user
|
20
|
+
api_client
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def api_client
|
26
|
+
@api_client ||= request.env[Stitches.configuration.env_var_to_hold_api_client]
|
27
|
+
# Use this if you want to look up the ApiClient instead of using the one placed into the env
|
28
|
+
# @api_client ||= ApiClient.find(request.env[Stitches.configuration.env_var_to_hold_api_client_primary_key])
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class Api::V1::HellosController < Api::ApiController
|
2
|
+
def show
|
3
|
+
name = request.env[Stitches.configuration.env_var_to_hold_api_client]&.name || "NameNotFound"
|
4
|
+
id = request.env[Stitches.configuration.env_var_to_hold_api_client_primary_key] || "IdNotFound"
|
5
|
+
render json: { hello: "Hello #{name}, your id is #{id}" }
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Api::V1::PingsController < Api::ApiController
|
2
|
+
|
3
|
+
def create
|
4
|
+
if ping_params[:error]
|
5
|
+
render json: { errors: Stitches::Errors.new([ Stitches::Error.new(code: "test", message: ping_params[:error]) ])} , status: 422
|
6
|
+
else
|
7
|
+
render json: { ping: { status: "ok" } }, status: (ping_params[:status] || "201").to_i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def ping_params
|
14
|
+
params.permit(:error, :status)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class Api::V2::HellosController < Api::ApiController
|
2
|
+
def show
|
3
|
+
name = request.env[Stitches.configuration.env_var_to_hold_api_client]&.name || "NameNotFound"
|
4
|
+
id = request.env[Stitches.configuration.env_var_to_hold_api_client_primary_key] || "IdNotFound"
|
5
|
+
render json: { hello: "Greetings #{name}, your id is #{id}" }
|
6
|
+
end
|
7
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Api::V2::PingsController < Api::ApiController
|
2
|
+
|
3
|
+
def create
|
4
|
+
if ping_params[:error]
|
5
|
+
render json: { errors: Stitches::Errors.new([ Stitches::Error.new(code: "test", message: ping_params[:error]) ])} , status: 422
|
6
|
+
else
|
7
|
+
render json: { ping: { status_v2: "ok" } }, status: (ping_params[:status] || "201").to_i
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def ping_params
|
14
|
+
params.permit(:error, :status)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
# path to your application root.
|
5
|
+
APP_ROOT = File.expand_path('..', __dir__)
|
6
|
+
|
7
|
+
def system!(*args)
|
8
|
+
system(*args) || abort("\n== Command #{args} failed ==")
|
9
|
+
end
|
10
|
+
|
11
|
+
FileUtils.chdir APP_ROOT do
|
12
|
+
# This script is a way to set up or update your development environment automatically.
|
13
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
14
|
+
# Add necessary setup steps to this file.
|
15
|
+
|
16
|
+
puts '== Installing dependencies =='
|
17
|
+
system! 'gem install bundler --conservative'
|
18
|
+
system('bundle check') || system!('bundle install')
|
19
|
+
|
20
|
+
# puts "\n== Copying sample files =="
|
21
|
+
# unless File.exist?('config/database.yml')
|
22
|
+
# FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
|
23
|
+
# end
|
24
|
+
|
25
|
+
puts "\n== Preparing database =="
|
26
|
+
system! 'bin/rails db:prepare'
|
27
|
+
|
28
|
+
puts "\n== Removing old logs and tempfiles =="
|
29
|
+
system! 'bin/rails log:clear tmp:clear'
|
30
|
+
|
31
|
+
puts "\n== Restarting application server =="
|
32
|
+
system! 'bin/rails restart'
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "boot"
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
# Pick the frameworks you want:
|
5
|
+
require "active_model/railtie"
|
6
|
+
require "active_job/railtie"
|
7
|
+
require "active_record/railtie"
|
8
|
+
require "active_storage/engine"
|
9
|
+
require "action_controller/railtie"
|
10
|
+
# require "action_mailer/railtie"
|
11
|
+
require "action_mailbox/engine"
|
12
|
+
require "action_text/engine"
|
13
|
+
require "action_view/railtie"
|
14
|
+
# require "action_cable/engine"
|
15
|
+
require "sprockets/railtie"
|
16
|
+
require "rails/test_unit/railtie"
|
17
|
+
|
18
|
+
# Require the gems listed in Gemfile, including any gems
|
19
|
+
# you've limited to :test, :development, or :production.
|
20
|
+
Bundler.require(*Rails.groups)
|
21
|
+
|
22
|
+
module FakeApp
|
23
|
+
class Application < Rails::Application
|
24
|
+
# Initialize configuration defaults for originally generated Rails version.
|
25
|
+
config.load_defaults 6.0
|
26
|
+
|
27
|
+
# Configuration for the application, engines, and railties goes here.
|
28
|
+
#
|
29
|
+
# These settings can be overridden in specific environments using the files
|
30
|
+
# in config/environments, which are processed later.
|
31
|
+
#
|
32
|
+
# config.time_zone = "Central Time (US & Canada)"
|
33
|
+
# config.eager_load_paths << Rails.root.join("extras")
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
1V1LD3DAIWjwHRquoRQBqr5cV/J7VMKuSfze36/aKJmPKzv5G6vQnrSpybKvTMY1Q29EEL/T3uGjj1wNuCAjh6eGWXXDDLVH85GlXw9qpHulWv36Dnr9xL9OQNvMRCKOrUuR3CJm4A4Fw9qC7zPTSHN2WhcxXNr1wVW1shJEWLW1eUzwRS3c3njC8KK3BCqktQK0MZhM0CryIxbZsi57VY8gZp0FegdOJGw2mASdYj2jGzEdNuyRMvgCOT8sXwgmMC3QV0v95w/M1AS2OqHsO7ndHfymBh8+qmEbHo74+w3aEkZ0Ct+mp49ROH2ZrZFRw9BWZ2T8gamLad3whIOzVGA4XI15hlcJGV9GWdbnHkLCHv9Rj+0Av09asKfJMnWW32yPpO79w88BAEd8I2ZhZNGcFLpYisQljXQA--HOld8JMRchEcQETs--oo5IsQMkFW/wZJKDvyInew==
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# SQLite. Versions 3.8.0 and up are supported.
|
2
|
+
# gem install sqlite3
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem 'sqlite3'
|
6
|
+
#
|
7
|
+
default: &default
|
8
|
+
adapter: sqlite3
|
9
|
+
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
|
10
|
+
timeout: 5000
|
11
|
+
|
12
|
+
development:
|
13
|
+
<<: *default
|
14
|
+
database: db/development.sqlite3
|
15
|
+
|
16
|
+
# Warning: The database defined as "test" will be erased and
|
17
|
+
# re-generated from your development database when you run "rake".
|
18
|
+
# Do not set this db to the same as development or production.
|
19
|
+
test:
|
20
|
+
<<: *default
|
21
|
+
database: db/test.sqlite3
|
22
|
+
|
23
|
+
production:
|
24
|
+
<<: *default
|
25
|
+
database: db/production.sqlite3
|