json_api_client 1.8.0 → 1.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed66b4d235079e662896ac7076427c21c716706c
4
- data.tar.gz: c70ff83b6e97b0671d584e68fc6958b41bd75246
3
+ metadata.gz: 26efa266b2d3eb7d2b504738b19392474c832b02
4
+ data.tar.gz: 5b60463dae1806e7318298cbd58ab5ce968453ae
5
5
  SHA512:
6
- metadata.gz: 57f163489d42ceff20dc4ab15de433c5d30af28daa0332d9bef2a990dc398de3b92d9f8b2d1e6b947943d88f8b031b533bb55fcfb406f79fde020d1b1517e42d
7
- data.tar.gz: 5b431c9c1e10f1197bff2558d776f92ff9ecec69cb484a6c603e07d47ef1ae03bc00a2511b9f7849a17d7ba5e9fb85617ed72fe82ace564a78ec9fdbb9a641f5
6
+ metadata.gz: 5830accd29e4821e85a32c0d39e650cc6603882a0022f9fe8cb633ec60c3efc030cc36d6d11d931ffd10cf38b4272ff3bac3184ca1547f81fe53b8071f92bbec
7
+ data.tar.gz: 487d5411c3f399a737b72c0ff007076f71e92ab84b93fca19a9d3e54f9b345082358e9b98340ed7a5bfdd543f994ee4bac5be37759ace8ded75d74824b177e21
data/README.md CHANGED
@@ -474,6 +474,44 @@ module MyApi
474
474
  end
475
475
  ```
476
476
 
477
+ ##### Custom status handler
478
+
479
+ You can change handling of response status using `connection_options`. For example you can override 400 status handling.
480
+ By default it raises `JsonApiClient::Errors::ClientError` but you can skip exception if you want to process errors from the server.
481
+ You need to provide a `proc` which should call `throw(:handled)` default handler for this status should be skipped.
482
+ ```ruby
483
+ class ApiBadRequestHandler
484
+ def self.call(_env)
485
+ # do not raise exception
486
+ end
487
+ end
488
+
489
+ class CustomUnauthorizedError < StandardError
490
+ attr_reader :env
491
+
492
+ def initialize(env)
493
+ @env = env
494
+ super('not authorized')
495
+ end
496
+ end
497
+
498
+ MyApi::Base.connection_options[:status_handlers] = {
499
+ 400 => ApiBadRequestHandler,
500
+ 401 => ->(env) { raise CustomUnauthorizedError, env }
501
+ }
502
+
503
+ module MyApi
504
+ class User < Base
505
+ # will use the customized status_handlers
506
+ end
507
+ end
508
+
509
+ user = MyApi::User.create(name: 'foo')
510
+ # server responds with { errors: [ { detail: 'bad request' } ] }
511
+ user.errors.messages # { base: ['bad request'] }
512
+ # on 401 it will raise CustomUnauthorizedError instead of JsonApiClient::Errors::NotAuthorized
513
+ ```
514
+
477
515
  ##### Specifying an HTTP Proxy
478
516
 
479
517
  All resources have a class method ```connection_options``` used to pass options to the JsonApiClient::Connection initializer.
@@ -553,6 +591,22 @@ class MyApi::Base < JsonApiClient::Resource
553
591
  end
554
592
  ```
555
593
 
594
+ ### Custom type
595
+
596
+ If your model must be named differently from classified type of resource you can easily customize it.
597
+ It will work both for defined and not defined relationships
598
+
599
+ ```ruby
600
+ class MyApi::Base < JsonApiClient::Resource
601
+ resolve_custom_type 'document--files', 'File'
602
+ end
603
+
604
+ class MyApi::File < MyApi::Base
605
+ def self.resource_name
606
+ 'document--files'
607
+ end
608
+ end
609
+ ```
556
610
 
557
611
  ### Type Casting
558
612
 
@@ -7,10 +7,12 @@ module JsonApiClient
7
7
  site = options.fetch(:site)
8
8
  connection_options = options.slice(:proxy, :ssl, :request, :headers, :params)
9
9
  adapter_options = Array(options.fetch(:adapter, Faraday.default_adapter))
10
+ status_middleware_options = {}
11
+ status_middleware_options[:custom_handlers] = options[:status_handlers] if options[:status_handlers].present?
10
12
  @faraday = Faraday.new(site, connection_options) do |builder|
11
13
  builder.request :json
12
14
  builder.use Middleware::JsonRequest
13
- builder.use Middleware::Status
15
+ builder.use Middleware::Status, status_middleware_options
14
16
  builder.use Middleware::ParseJson
15
17
  builder.adapter(*adapter_options)
16
18
  end
@@ -18,6 +18,10 @@ module JsonApiClient
18
18
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
19
19
  end
20
20
 
21
+ def forget_change!(attr)
22
+ @changed_attributes.delete(attr.to_s)
23
+ end
24
+
21
25
  def set_all_attributes_dirty
22
26
  attributes.each do |k, v|
23
27
  set_attribute_was(k, v)
@@ -68,4 +72,4 @@ module JsonApiClient
68
72
 
69
73
  end
70
74
  end
71
- end
75
+ end
@@ -1,6 +1,11 @@
1
1
  module JsonApiClient
2
2
  module Middleware
3
3
  class Status < Faraday::Middleware
4
+ def initialize(app, options)
5
+ super(app)
6
+ @options = options
7
+ end
8
+
4
9
  def call(environment)
5
10
  @app.call(environment).on_complete do |env|
6
11
  handle_status(env[:status], env)
@@ -15,9 +20,16 @@ module JsonApiClient
15
20
  raise Errors::ConnectionError.new environment, e.to_s
16
21
  end
17
22
 
18
- protected
23
+ private
24
+
25
+ def custom_handler_for(code)
26
+ @options.fetch(:custom_handlers, {})[code]
27
+ end
19
28
 
20
29
  def handle_status(code, env)
30
+ custom_handler = custom_handler_for(code)
31
+ return custom_handler.call(env) if custom_handler.present?
32
+
21
33
  case code
22
34
  when 200..399
23
35
  when 401
@@ -35,6 +35,7 @@ module JsonApiClient
35
35
  :request_params_class,
36
36
  :keep_request_params,
37
37
  :search_included_in_result_set,
38
+ :custom_type_to_class,
38
39
  instance_accessor: false
39
40
  class_attribute :add_defaults_to_changes,
40
41
  instance_writer: false
@@ -52,6 +53,7 @@ module JsonApiClient
52
53
  self.keep_request_params = false
53
54
  self.add_defaults_to_changes = false
54
55
  self.search_included_in_result_set = false
56
+ self.custom_type_to_class = {}
55
57
 
56
58
  #:underscored_key, :camelized_key, :dasherized_key, or custom
57
59
  self.json_key_format = :underscored_key
@@ -63,6 +65,11 @@ module JsonApiClient
63
65
  extend Forwardable
64
66
  def_delegators :_new_scope, :where, :order, :includes, :select, :all, :paginate, :page, :with_params, :first, :find, :last
65
67
 
68
+ def resolve_custom_type(type_name, class_name)
69
+ classified_type = key_formatter.unformat(type_name.to_s).singularize.classify
70
+ self.custom_type_to_class = custom_type_to_class.merge(classified_type => class_name.to_s)
71
+ end
72
+
66
73
  # The table name for this resource. i.e. Article -> articles, Person -> people
67
74
  #
68
75
  # @return [String] The table name for this resource
@@ -322,6 +329,7 @@ module JsonApiClient
322
329
  self.links = self.class.linker.new(params.delete(:links) || {})
323
330
  self.relationships = self.class.relationship_linker.new(self.class, params.delete(:relationships) || {})
324
331
  self.attributes = self.class.default_attributes.merge params.except(*self.class.prefix_params)
332
+ self.forget_change!(:type)
325
333
  self.__belongs_to_params = params.slice(*self.class.prefix_params)
326
334
 
327
335
  setup_default_properties
@@ -394,7 +402,7 @@ module JsonApiClient
394
402
  #
395
403
  # @return [Hash] Representation of this object as JSONAPI object
396
404
  def as_json_api(*)
397
- attributes.slice(:id, :type).tap do |h|
405
+ attributes.slice(self.class.primary_key, :type).tap do |h|
398
406
  relationships_for_serialization.tap do |r|
399
407
  h[:relationships] = self.class.key_formatter.format_keys(r) unless r.empty?
400
408
  end
@@ -403,11 +411,11 @@ module JsonApiClient
403
411
  end
404
412
 
405
413
  def as_json(*)
406
- attributes.slice(:id, :type).tap do |h|
414
+ attributes.slice(self.class.primary_key, :type).tap do |h|
407
415
  relationships.as_json.tap do |r|
408
416
  h[:relationships] = r unless r.empty?
409
417
  end
410
- h[:attributes] = attributes.except(:id, :type).as_json
418
+ h[:attributes] = attributes.except(self.class.primary_key, :type).as_json
411
419
  end
412
420
  end
413
421
 
@@ -504,7 +512,7 @@ module JsonApiClient
504
512
  end
505
513
 
506
514
  def path_attributes
507
- _belongs_to_params.merge attributes.slice('id').symbolize_keys
515
+ _belongs_to_params.merge attributes.slice( self.class.primary_key ).symbolize_keys
508
516
  end
509
517
 
510
518
  protected
@@ -2,6 +2,7 @@ module JsonApiClient
2
2
  module Utils
3
3
 
4
4
  def self.compute_type(klass, type_name)
5
+ return klass.custom_type_to_class.fetch(type_name).constantize if klass.custom_type_to_class.key?(type_name)
5
6
  # If the type is prefixed with a scope operator then we assume that
6
7
  # the type_name is an absolute reference.
7
8
  return type_name.constantize if type_name.match(/^::/)
@@ -1,3 +1,3 @@
1
1
  module JsonApiClient
2
- VERSION = "1.8.0"
2
+ VERSION = "1.9.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Ching
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-23 00:00:00.000000000 Z
11
+ date: 2019-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport