json_api_responders 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c661ab2ab937e5f41f6f4447f4223def1f55c8bf
4
+ data.tar.gz: 0ffdc9290b732bff8e65f4df240cd5b37a1b2aad
5
+ SHA512:
6
+ metadata.gz: 34836428bc2a2633118dade15b90bfb5e3dbbbbb671427b3f7d44b3beea7970a7ba0f1d4c331274e4d1e7bd2e4d5cfcf6ad34bf215073d35365b9144d480441c
7
+ data.tar.gz: 5e6b7b3e90442b7de163178ea0b769dc9d0417f60b10e0b2219666eb4401d36f588c55a2528c8352d6e6edd98517316d17b430e853de0a339d1d2306354d5c4d
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in json_api_responders.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # JsonApiResponders
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/json_api_responders`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'json_api_responders'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install json_api_responders
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/json_api_responders.
36
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "json_api_responders"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'json_api_responders/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'json_api_responders'
8
+ spec.version = JsonApiResponders::VERSION
9
+ spec.authors = ['Stanko Krtalić Rusendić']
10
+ spec.email = ['stanko.krtalic@gmail.com']
11
+
12
+ spec.summary = 'Automatically respond to JSON::API requests'
13
+ spec.description = 'Automatically respond to JSON::API requests'
14
+ spec.homepage = 'https://github.com/infinum/json_api_responders'
15
+
16
+ if spec.respond_to?(:metadata)
17
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
+ else
19
+ fail('RubyGems 2.0 or newer is required to protect against public gem pushes.')
20
+ end
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
23
+ f.match(%r{^(test|spec|features)/})
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_development_dependency 'bundler', '~> 1.11'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.0'
32
+ end
@@ -0,0 +1,64 @@
1
+ require 'json_api_responders/version'
2
+ require 'json_api_responders/errors'
3
+ require 'json_api_responders/responder'
4
+
5
+ module JsonApiResponders
6
+ def self.included(base)
7
+ base.rescue_from ActiveRecord::RecordNotFound, with: :record_not_found!
8
+ redefine_authorization(base)
9
+ end
10
+
11
+ def self.redefine_authorization(base)
12
+ return unless base.instance_methods.include?(:authenticate_user_from_token!)
13
+
14
+ base.class_eval do
15
+ alias_method(:_authenticate_from_token!, :authenticate_user_from_token!)
16
+
17
+ define_method :authenticate_user_from_token! do
18
+ result = catch(:warden) { _authenticate_from_token! }
19
+
20
+ return unless result
21
+ respond_with_error(:unauthorized)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def respond_with_error(error_type)
29
+ case error_type
30
+ when :unauthorized
31
+ Responder.new(nil, controller: self, status: :forbidden).unauthorized
32
+ when :not_found
33
+ Responder.new(nil, controller: self, status: :not_found).not_found
34
+ end
35
+ end
36
+
37
+ def respond_with(resource, options = {})
38
+ options = {
39
+ namespace: self.class.parent,
40
+ status: :ok,
41
+ params: params,
42
+ controller: self
43
+ }.merge(options)
44
+
45
+ Responder.new(resource, options).respond!
46
+ end
47
+
48
+ def record_not_found!
49
+ respond_with_error(:not_found)
50
+ end
51
+
52
+ def deserialized_params
53
+ @_deserialized_options ||=
54
+ ActionController::Parameters.new(
55
+ ActiveModelSerializers::Deserialization.jsonapi_parse(
56
+ params, json_api_parse_options
57
+ )
58
+ )
59
+ end
60
+
61
+ def json_api_parse_options
62
+ {}
63
+ end
64
+ end
@@ -0,0 +1,37 @@
1
+ module JsonApiResponders
2
+ module Errors
3
+ class UnknownHTTPStatus < StandardError
4
+ attr_reader :status
5
+
6
+ def initialize(status)
7
+ @status = status
8
+ super(message)
9
+ end
10
+
11
+ def message
12
+ status_symbols =
13
+ Rack::Utils::SYMBOL_TO_STATUS_CODE.keys.map(&:to_s)
14
+ status_codes =
15
+ Rack::Utils::SYMBOL_TO_STATUS_CODE.invert.keys.map(&:to_s)
16
+ statuses = (status_symbols + status_codes).join(', ')
17
+
18
+ "Unknown HTTP status code '#{status}'.\n"\
19
+ "Available status codes and symbols are: #{statuses}"
20
+ end
21
+ end
22
+
23
+ class UnknownAction < StandardError
24
+ attr_reader :action
25
+
26
+ def initialize(action)
27
+ @action = action
28
+ super(message)
29
+ end
30
+
31
+ def message
32
+ "Unknown controller action '#{action}'.\n"\
33
+ "Accepted actions are #{JsonApi::Responder::ACTIONS.join(', ')}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,90 @@
1
+ require 'json_api_responders/responder/actions'
2
+ require 'json_api_responders/responder/sanitizers'
3
+
4
+ module JsonApiResponders
5
+ class Responder
6
+ include Actions
7
+
8
+ attr_accessor :errors
9
+ attr_accessor :status
10
+ attr_reader :resource
11
+ attr_reader :options
12
+ attr_reader :params
13
+ attr_reader :controller
14
+ attr_reader :namespace
15
+
16
+ def initialize(resource, options = {})
17
+ @resource = resource
18
+ @options = options
19
+ self.status = @options[:status]
20
+ @params = @options[:params]
21
+ @controller = @options[:controller]
22
+ @namespace = @options[:namespace]
23
+ end
24
+
25
+ def respond!
26
+ render_response
27
+ end
28
+
29
+ def not_found
30
+ self.errors = {
31
+ title: I18n.t('json_api.errors.not_found.title'),
32
+ status: status
33
+ }
34
+
35
+ render_error
36
+ end
37
+
38
+ def unauthorized
39
+ self.errors = {
40
+ title: I18n.t('json_api.errors.unauthorized.title'),
41
+ status: status
42
+ }
43
+
44
+ render_error
45
+ end
46
+
47
+ private
48
+
49
+ def status=(status)
50
+ @status = Sanitizers.status(status)
51
+ end
52
+
53
+ def action
54
+ params[:action]
55
+ end
56
+
57
+ def render_response
58
+ return send("respond_to_#{action}_action") if action.in?(ACTIONS)
59
+ raise(JsonApi::Errors::UnknownAction, action)
60
+ end
61
+
62
+ def render_error
63
+ controller.render(error_render_options)
64
+ end
65
+
66
+ def error_render_options
67
+ render_options.merge(
68
+ json: error_messages
69
+ )
70
+ end
71
+
72
+ def render_options
73
+ {
74
+ status: status,
75
+ content_type: 'application/vnd.api+json'
76
+ }
77
+ end
78
+
79
+ def error_messages
80
+ return errors if errors
81
+
82
+ resource.errors.full_messages.map do |message|
83
+ {
84
+ title: message,
85
+ status: status
86
+ }
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,72 @@
1
+ module JsonApiResponders
2
+ class Responder
3
+ module Actions
4
+ ACTIONS = %w(index show create update destroy).freeze
5
+
6
+ def respond_to_index_action
7
+ self.status ||= :ok
8
+ render_resource
9
+ end
10
+
11
+ def respond_to_show_action
12
+ self.status ||= :ok
13
+ render_resource
14
+ end
15
+
16
+ def respond_to_create_action
17
+ if resource.persisted? && resource.valid?
18
+ self.status ||= :created
19
+ render_resource
20
+ else
21
+ self.status ||= :conflict
22
+ render_error
23
+ end
24
+ end
25
+
26
+ def respond_to_update_action
27
+ if resource.valid?
28
+ self.status ||= :ok
29
+ render_resource
30
+ else
31
+ self.status ||= :conflict
32
+ render_error
33
+ end
34
+ end
35
+
36
+ def respond_to_destroy_action
37
+ self.status ||= :no_content
38
+ controller.head(status, render_options)
39
+ end
40
+
41
+ def render_resource
42
+ controller.render(resource_render_options)
43
+ end
44
+
45
+ def resource_render_options
46
+ serializer_key = relation? ? :each_serializer : :serializer
47
+
48
+ render_options.merge(
49
+ json: resource,
50
+ serializer_key => serializer_class
51
+ )
52
+ end
53
+
54
+ def serializer_class
55
+ options[:serializer] ||=
56
+ [
57
+ namespace,
58
+ "#{resource_class}Serializer"
59
+ ].compact.join('::').constantize
60
+ end
61
+
62
+ def resource_class
63
+ return resource.model if relation?
64
+ resource.class
65
+ end
66
+
67
+ def relation?
68
+ resource.is_a?(ActiveRecord::Relation)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,18 @@
1
+ module JsonApiResponders
2
+ class Responder
3
+ module Sanitizers
4
+ def self.status(status)
5
+ if status.is_a?(Integer)
6
+ status = Rack::Utils::SYMBOL_TO_STATUS_CODE.invert[status]
7
+ end
8
+
9
+ if status.nil? || !status.is_a?(Symbol) ||
10
+ Rack::Utils::SYMBOL_TO_STATUS_CODE[status].nil?
11
+ raise(JsonApi::Errors::UnknownHTTPStatus, status)
12
+ end
13
+
14
+ status
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ module JsonApiResponders
2
+ MAJOR = 1
3
+ MINOR = 0
4
+ PATCH = 0
5
+ VERSION = [MAJOR, MINOR, PATCH].join('.').freeze
6
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json_api_responders
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Stanko Krtalić Rusendić
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-06-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Automatically respond to JSON::API requests
56
+ email:
57
+ - stanko.krtalic@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - README.md
67
+ - Rakefile
68
+ - bin/console
69
+ - bin/setup
70
+ - json_api_responders.gemspec
71
+ - lib/json_api_responders.rb
72
+ - lib/json_api_responders/errors.rb
73
+ - lib/json_api_responders/responder.rb
74
+ - lib/json_api_responders/responder/actions.rb
75
+ - lib/json_api_responders/responder/sanitizers.rb
76
+ - lib/json_api_responders/version.rb
77
+ homepage: https://github.com/infinum/json_api_responders
78
+ licenses: []
79
+ metadata:
80
+ allowed_push_host: https://rubygems.org
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubyforge_project:
97
+ rubygems_version: 2.5.1
98
+ signing_key:
99
+ specification_version: 4
100
+ summary: Automatically respond to JSON::API requests
101
+ test_files: []
102
+ has_rdoc: