json_api_client 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
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