simple_jsonapi_rails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +132 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +5 -0
- data/Jenkinsfile +92 -0
- data/LICENSE.txt +22 -0
- data/README.md +245 -0
- data/Rakefile +10 -0
- data/lib/simple_jsonapi/errors/active_model_error.rb +21 -0
- data/lib/simple_jsonapi/errors/active_model_error_serializer.rb +15 -0
- data/lib/simple_jsonapi/errors/active_record/record_not_found_serializer.rb +15 -0
- data/lib/simple_jsonapi/rails/action_controller/jsonapi_helper.rb +122 -0
- data/lib/simple_jsonapi/rails/action_controller/request_validator.rb +40 -0
- data/lib/simple_jsonapi/rails/action_controller.rb +44 -0
- data/lib/simple_jsonapi/rails/extensions/routing.rb +57 -0
- data/lib/simple_jsonapi/rails/extensions.rb +13 -0
- data/lib/simple_jsonapi/rails/railtie.rb +34 -0
- data/lib/simple_jsonapi/rails/test_helpers.rb +20 -0
- data/lib/simple_jsonapi/rails/version.rb +5 -0
- data/lib/simple_jsonapi/rails.rb +13 -0
- data/lib/simple_jsonapi_rails.rb +4 -0
- data/simple_jsonapi_rails.gemspec +33 -0
- data/test/action_controller_test.rb +299 -0
- data/test/dummy/.gitignore +23 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/controllers/api_controller.rb +3 -0
- data/test/dummy/app/controllers/orders/relationships/items_controller.rb +10 -0
- data/test/dummy/app/controllers/orders_controller.rb +38 -0
- data/test/dummy/app/models/order.rb +4 -0
- data/test/dummy/app/serializers/order_serializer.rb +6 -0
- data/test/dummy/config/application.rb +13 -0
- data/test/dummy/config/boot.rb +3 -0
- data/test/dummy/config/database.yml +7 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +44 -0
- data/test/dummy/config/environments/test.rb +44 -0
- data/test/dummy/config/initializers/.keep +0 -0
- data/test/dummy/config/locales/en.yml +2 -0
- data/test/dummy/config/puma.rb +56 -0
- data/test/dummy/config/routes.rb +5 -0
- data/test/dummy/config/secrets.yml +24 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/db/migrate/20170719143227_create_orders.rb +10 -0
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/tmp/.keep +0 -0
- data/test/errors/active_model_error_serializer_test.rb +47 -0
- data/test/errors/active_model_error_test.rb +46 -0
- data/test/errors/active_record/record_not_found_serializer_test.rb +33 -0
- data/test/test_helper.rb +35 -0
- metadata +284 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
2
|
+
#
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
5
|
+
# git config --global core.excludesfile '~/.gitignore_global'
|
6
|
+
|
7
|
+
# Ignore bundler config.
|
8
|
+
/.bundle
|
9
|
+
|
10
|
+
# Ignore the default SQLite database.
|
11
|
+
/db/*.sqlite3
|
12
|
+
/db/*.sqlite3-journal
|
13
|
+
|
14
|
+
# Ignore all logfiles and tempfiles.
|
15
|
+
/log/*
|
16
|
+
/tmp/*
|
17
|
+
!/log/.keep
|
18
|
+
!/tmp/.keep
|
19
|
+
|
20
|
+
/node_modules
|
21
|
+
/yarn-error.log
|
22
|
+
|
23
|
+
.byebug_history
|
data/test/dummy/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class OrdersController < ApiController
|
2
|
+
jsonapi_deserialize :order
|
3
|
+
|
4
|
+
SORT_OPTIONS = {
|
5
|
+
customer_name: "lower(customer_name)",
|
6
|
+
date: "date",
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
def index
|
10
|
+
orders = Order.all
|
11
|
+
# order(jsonapi.sort_sql(SORT_OPTIONS, :name, :asc)).
|
12
|
+
# paginate(jsonapi.will_paginate_options)
|
13
|
+
|
14
|
+
render jsonapi_resources: orders, serializer: OrderSerializer,
|
15
|
+
include: jsonapi.include_params
|
16
|
+
end
|
17
|
+
|
18
|
+
def show
|
19
|
+
order = Order.find(params[:id])
|
20
|
+
render jsonapi_resource: order, serializer: OrderSerializer
|
21
|
+
end
|
22
|
+
|
23
|
+
def create
|
24
|
+
order = Order.create!(order_params)
|
25
|
+
render jsonapi_resource: order, serializer: OrderSerializer, status: :created
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
order = Order.find(params[:id]).update!(order_params)
|
30
|
+
render jsonapi_resource: order, serializer: OrderSerializer, status: :ok
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def order_params
|
36
|
+
params.require(:order).permit(:customer_name, :date)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative 'boot'
|
2
|
+
|
3
|
+
require 'rails/all'
|
4
|
+
|
5
|
+
# Require the gems listed in Gemfile, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(*Rails.groups)
|
8
|
+
|
9
|
+
module Dummy
|
10
|
+
class Application < Rails::Application
|
11
|
+
config.load_defaults 5.1
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Rails.application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the web server when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
# Do not eager load code on boot.
|
10
|
+
config.eager_load = false
|
11
|
+
|
12
|
+
# Show full error reports.
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
|
15
|
+
# Enable/disable caching. By default caching is disabled.
|
16
|
+
config.action_controller.perform_caching = false
|
17
|
+
config.cache_store = :null_store
|
18
|
+
|
19
|
+
# Don't care if the mailer can't send.
|
20
|
+
config.action_mailer.raise_delivery_errors = false
|
21
|
+
|
22
|
+
config.action_mailer.perform_caching = false
|
23
|
+
|
24
|
+
# Print deprecation notices to the Rails logger.
|
25
|
+
config.active_support.deprecation = :log
|
26
|
+
|
27
|
+
# Raise an error on page load if there are pending migrations.
|
28
|
+
config.active_record.migration_error = :page_load
|
29
|
+
|
30
|
+
# Debug mode disables concatenation and preprocessing of assets.
|
31
|
+
# This option may cause significant delays in view rendering with a large
|
32
|
+
# number of complex assets.
|
33
|
+
config.assets.debug = true
|
34
|
+
|
35
|
+
# Suppress logger output for asset requests.
|
36
|
+
config.assets.quiet = true
|
37
|
+
|
38
|
+
# Raises error for missing translations
|
39
|
+
# config.action_view.raise_on_missing_translations = true
|
40
|
+
|
41
|
+
# Use an evented file watcher to asynchronously detect changes in source code,
|
42
|
+
# routes, locales, etc. This feature depends on the listen gem.
|
43
|
+
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Rails.application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
11
|
+
# just for the purpose of running a single test. If you are using a tool that
|
12
|
+
# preloads Rails for running tests, you may have to set it to true.
|
13
|
+
config.eager_load = false
|
14
|
+
|
15
|
+
# Configure public file server for tests with Cache-Control for performance.
|
16
|
+
config.public_file_server.enabled = true
|
17
|
+
config.public_file_server.headers = {
|
18
|
+
'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}",
|
19
|
+
}
|
20
|
+
|
21
|
+
# Show full error reports and disable caching.
|
22
|
+
config.consider_all_requests_local = true
|
23
|
+
config.action_controller.perform_caching = false
|
24
|
+
|
25
|
+
# Raise exceptions instead of rendering exception templates.
|
26
|
+
config.action_dispatch.show_exceptions = false
|
27
|
+
|
28
|
+
# Disable request forgery protection in test environment.
|
29
|
+
config.action_controller.allow_forgery_protection = false
|
30
|
+
config.action_mailer.perform_caching = false
|
31
|
+
|
32
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
33
|
+
# The :test delivery method accumulates sent emails in the
|
34
|
+
# ActionMailer::Base.deliveries array.
|
35
|
+
config.action_mailer.delivery_method = :test
|
36
|
+
|
37
|
+
# Print deprecation notices to the stderr.
|
38
|
+
config.active_support.deprecation = :stderr
|
39
|
+
|
40
|
+
# Raises error for missing translations
|
41
|
+
# config.action_view.raise_on_missing_translations = true
|
42
|
+
|
43
|
+
Rails.application.routes.default_url_options = { host: 'localhost', port: 80, protocol: 'http' }
|
44
|
+
end
|
File without changes
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Puma can serve each request in a thread from an internal thread pool.
|
2
|
+
# The `threads` method setting takes two numbers: a minimum and maximum.
|
3
|
+
# Any libraries that use thread pools should be configured to match
|
4
|
+
# the maximum value specified for Puma. Default is set to 5 threads for minimum
|
5
|
+
# and maximum; this matches the default thread size of Active Record.
|
6
|
+
#
|
7
|
+
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
|
8
|
+
threads threads_count, threads_count
|
9
|
+
|
10
|
+
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
|
11
|
+
#
|
12
|
+
port ENV.fetch("PORT") { 3000 }
|
13
|
+
|
14
|
+
# Specifies the `environment` that Puma will run in.
|
15
|
+
#
|
16
|
+
environment ENV.fetch("RAILS_ENV") { "development" }
|
17
|
+
|
18
|
+
# Specifies the number of `workers` to boot in clustered mode.
|
19
|
+
# Workers are forked webserver processes. If using threads and workers together
|
20
|
+
# the concurrency of the application would be max `threads` * `workers`.
|
21
|
+
# Workers do not work on JRuby or Windows (both of which do not support
|
22
|
+
# processes).
|
23
|
+
#
|
24
|
+
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
|
25
|
+
|
26
|
+
# Use the `preload_app!` method when specifying a `workers` number.
|
27
|
+
# This directive tells Puma to first boot the application and load code
|
28
|
+
# before forking the application. This takes advantage of Copy On Write
|
29
|
+
# process behavior so workers use less memory. If you use this option
|
30
|
+
# you need to make sure to reconnect any threads in the `on_worker_boot`
|
31
|
+
# block.
|
32
|
+
#
|
33
|
+
# preload_app!
|
34
|
+
|
35
|
+
# If you are preloading your application and using Active Record, it's
|
36
|
+
# recommended that you close any connections to the database before workers
|
37
|
+
# are forked to prevent connection leakage.
|
38
|
+
#
|
39
|
+
# before_fork do
|
40
|
+
# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
|
41
|
+
# end
|
42
|
+
|
43
|
+
# The code in the `on_worker_boot` will be called if you are using
|
44
|
+
# clustered mode by specifying a number of `workers`. After each worker
|
45
|
+
# process is booted, this block will be run. If you are using the `preload_app!`
|
46
|
+
# option, you will want to use this block to reconnect to any threads
|
47
|
+
# or connections that may have been created at application boot, as Ruby
|
48
|
+
# cannot share connections between processes.
|
49
|
+
#
|
50
|
+
# on_worker_boot do
|
51
|
+
# ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
|
55
|
+
# Allow puma to be restarted by `rails restart` command.
|
56
|
+
plugin :tmp_restart
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Your secret key is used for verifying the integrity of signed cookies.
|
4
|
+
# If you change this key, all old signed cookies will become invalid!
|
5
|
+
|
6
|
+
# Make sure the secret is at least 30 characters and all random,
|
7
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
8
|
+
# You can use `rails secret` to generate a secure secret key.
|
9
|
+
|
10
|
+
# Make sure the secrets in this file are kept private
|
11
|
+
# if you're sharing your code publicly.
|
12
|
+
|
13
|
+
# Shared secrets are available across all environments.
|
14
|
+
|
15
|
+
# shared:
|
16
|
+
# api_key: a1B2c3D4e5F6
|
17
|
+
|
18
|
+
# Environmental secrets are only available for that specific environment.
|
19
|
+
|
20
|
+
development:
|
21
|
+
secret_key_base: 3b243cd72ec1cc96362ffa02d3c7174630a78e52228ecce3fd5e247cf443a46725537f7fdeb9a0c824e8149c574c08216fef7909082e0dbd8fcf3973d1746ed3
|
22
|
+
|
23
|
+
test:
|
24
|
+
secret_key_base: 367e5a2da146fb0c1d51d9820b2f866688e7694209667dfdef3eb569ed98a3219ecb528a4c61920de021de9740a42784f8655e355c0850f109a8f855793de785
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# This file should contain all the record creation needed to seed the database with its default values.
|
2
|
+
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
|
3
|
+
#
|
4
|
+
# Examples:
|
5
|
+
#
|
6
|
+
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
|
7
|
+
# Character.create(name: 'Luke', movie: movies.first)
|
File without changes
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class ActiveModelErrorSerializerTest < Minitest::Spec
|
4
|
+
let(:attribute_error) do
|
5
|
+
SimpleJsonapi::Errors::ActiveModelError.new("the_attribute", "the_message", "the_pointer")
|
6
|
+
end
|
7
|
+
let(:generic_error) do
|
8
|
+
SimpleJsonapi::Errors::ActiveModelError.new(nil, "the_message", nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:serialized_attribute_error) do
|
12
|
+
SimpleJsonapi.render_errors(attribute_error).dig(:errors, 0)
|
13
|
+
end
|
14
|
+
let(:serialized_generic_error) do
|
15
|
+
SimpleJsonapi.render_errors(generic_error).dig(:errors, 0)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe SimpleJsonapi::Errors::ActiveModelErrorSerializer do
|
19
|
+
it "has a status of 422" do
|
20
|
+
assert_equal "422", serialized_attribute_error[:status]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "has a code of unprocessable_entity" do
|
24
|
+
assert_equal "unprocessable_entity", serialized_attribute_error[:code]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "has the attribute name in the title" do
|
28
|
+
assert_equal "Invalid the_attribute", serialized_attribute_error[:title]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "has a generic title if the attribute is blank" do
|
32
|
+
assert_equal "Invalid record", serialized_generic_error[:title]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has the full message as the detail" do
|
36
|
+
assert_equal "the_message", serialized_attribute_error[:detail]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "includes the source pointer" do
|
40
|
+
assert_equal "the_pointer", serialized_attribute_error.dig(:source, :pointer)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "ignores a missing source pointer" do
|
44
|
+
assert_nil serialized_generic_error.dig(:source, :pointer)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class ActiveModelErrorTest < Minitest::Spec
|
4
|
+
class Order
|
5
|
+
include ActiveModel::Model
|
6
|
+
attr_accessor :customer_name, :description
|
7
|
+
validates :customer_name, presence: true
|
8
|
+
validates :description, presence: true
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:invalid_order) { Order.new.tap(&:valid?) }
|
12
|
+
|
13
|
+
describe SimpleJsonapi::Errors::ActiveModelError do
|
14
|
+
describe "#initialize" do
|
15
|
+
let(:error) { SimpleJsonapi::Errors::ActiveModelError.new("the_attribute", "the_message", "the_pointer") }
|
16
|
+
|
17
|
+
it "takes an attribute, a message, and a pointer" do
|
18
|
+
assert_equal "the_attribute", error.attribute
|
19
|
+
assert_equal "the_message", error.message
|
20
|
+
assert_equal "the_pointer", error.pointer
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".from_errors" do
|
25
|
+
let(:pointer_mapping) do
|
26
|
+
{
|
27
|
+
customer_name: "/data/attributes/customer_name",
|
28
|
+
description: "/data/attributes/description",
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:errors) do
|
33
|
+
SimpleJsonapi::Errors::ActiveModelError.from_errors(invalid_order.errors, pointer_mapping)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "converts an ActiveModel::Errors object" do
|
37
|
+
assert_equal ["customer_name", "description"], errors.map(&:attribute).sort
|
38
|
+
assert_equal ["Customer name can't be blank", "Description can't be blank"], errors.map(&:message).sort
|
39
|
+
end
|
40
|
+
|
41
|
+
it "incorporates a pointer mapping" do
|
42
|
+
assert_equal ["/data/attributes/customer_name", "/data/attributes/description"], errors.map(&:pointer).sort
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
class ActiveRecord::RecordNotFoundSerializerTest < Minitest::Spec
|
4
|
+
let(:error) do
|
5
|
+
ActiveRecord::RecordNotFound.new("a message", "Thing", "id", 1)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:serialized_error) do
|
9
|
+
SimpleJsonapi.render_errors(error).dig(:errors, 0)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe SimpleJsonapi::Errors::ActiveRecord::RecordNotFoundSerializer do
|
13
|
+
it "has a status of 404" do
|
14
|
+
assert_equal "404", serialized_error[:status]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has a code of not_found" do
|
18
|
+
assert_equal "not_found", serialized_error[:code]
|
19
|
+
end
|
20
|
+
|
21
|
+
it "has a title of Not found" do
|
22
|
+
assert_equal "Not found", serialized_error[:title]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "has the full message as the detail" do
|
26
|
+
assert_equal "a message", serialized_error[:detail]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has the primary key as the source parameter" do
|
30
|
+
assert_equal "id", serialized_error[:source][:parameter]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
# Set up the dummy app
|
4
|
+
ENV['RAILS_ENV'] = 'test'
|
5
|
+
require_relative 'dummy/config/environment'
|
6
|
+
ActiveRecord::Migrator.migrate File.expand_path("dummy/db/migrate/", __dir__)
|
7
|
+
|
8
|
+
require 'active_support'
|
9
|
+
|
10
|
+
require 'minitest/autorun'
|
11
|
+
require 'minitest/spec'
|
12
|
+
require 'minitest/reporters'
|
13
|
+
require 'pry'
|
14
|
+
require 'pp'
|
15
|
+
|
16
|
+
require 'simple_jsonapi/rails'
|
17
|
+
require 'simple_jsonapi/rails/test_helpers'
|
18
|
+
|
19
|
+
if ENV['BUILD_NUMBER']
|
20
|
+
Minitest::Reporters.use!(
|
21
|
+
[MiniTest::Reporters::DefaultReporter.new, MiniTest::Reporters::JUnitReporter.new('test/reports')],
|
22
|
+
ENV,
|
23
|
+
Minitest.backtrace_filter,
|
24
|
+
)
|
25
|
+
else
|
26
|
+
Minitest::Reporters.use!(Minitest::Reporters::SpecReporter.new, ENV, Minitest.backtrace_filter)
|
27
|
+
end
|
28
|
+
|
29
|
+
class ActiveSupport::TestCase
|
30
|
+
extend Minitest::Spec::DSL
|
31
|
+
self.test_order = :random
|
32
|
+
|
33
|
+
include ActiveRecord::TestFixtures
|
34
|
+
self.use_transactional_tests = true
|
35
|
+
end
|