Skip to content

Commit a55c06c

Browse files
authored
Remove Errors namespace under Smithy::Client (#299)
1 parent fcb7fef commit a55c06c

File tree

26 files changed

+209
-197
lines changed

26 files changed

+209
-197
lines changed

gems/smithy-client/lib/smithy-client.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
require_relative 'smithy-client/block_io'
1313
require_relative 'smithy-client/configuration'
14+
require_relative 'smithy-client/dynamic_errors'
1415
require_relative 'smithy-client/endpoint_rules'
15-
require_relative 'smithy-client/errors'
1616
require_relative 'smithy-client/handler'
1717
require_relative 'smithy-client/handler_builder'
1818
require_relative 'smithy-client/handler_context'
@@ -26,6 +26,7 @@
2626
require_relative 'smithy-client/plugin'
2727
require_relative 'smithy-client/plugin_list'
2828
require_relative 'smithy-client/retry'
29+
require_relative 'smithy-client/service_error'
2930
require_relative 'smithy-client/util'
3031
require_relative 'smithy-client/input'
3132
require_relative 'smithy-client/output'
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# frozen_string_literal: true
2+
3+
module Smithy
4+
module Client
5+
# This module is mixed into another module, providing dynamic
6+
# error classes. Error classes all inherit from {ServiceError}.
7+
#
8+
# # Creates and returns the class
9+
# Weather::Errors::MyNewErrorClass
10+
#
11+
# Since the complete list of possible errors returned by services may
12+
# not be known, this allows us to create them as needed. This also
13+
# allows users to rescue errors by class without them being concrete
14+
# classes beforehand.
15+
#
16+
# @api private
17+
module DynamicErrors
18+
def self.extended(submodule)
19+
submodule.instance_variable_set('@const_set_mutex', Mutex.new)
20+
submodule.const_set(:ServiceError, Class.new(ServiceError))
21+
end
22+
23+
def const_missing(constant)
24+
set_error_constant(constant)
25+
end
26+
27+
# Given the name of a service and an error code, this method
28+
# returns an error class that extends {ServiceError}.
29+
#
30+
# Weather::Errors.error_class('NoSuchCity').new
31+
# #=> #<Weather::Errors::NoSuchCity>
32+
#
33+
# @api private
34+
def error_class(error_code)
35+
constant = error_class_constant(error_code)
36+
if error_const_set?(constant)
37+
err_class = const_get(constant)
38+
err_class.code = constant.to_s
39+
err_class
40+
else
41+
set_error_constant(constant)
42+
end
43+
end
44+
45+
private
46+
47+
# Convert an error code to an error class name/constant.
48+
# This requires filtering non-safe characters from the constant
49+
# name and ensuring it begins with an uppercase letter.
50+
#
51+
# @param [String] error_code
52+
# @return [Symbol] Returns a symbolized constant name for the given `error_code`.
53+
def error_class_constant(error_code)
54+
constant = error_code.to_s
55+
constant = constant.gsub(/https?:.*$/, '')
56+
constant = constant.gsub(/[^a-zA-Z0-9]/, '')
57+
constant = "Error#{constant}" unless constant.match(/^[a-z]/i)
58+
constant = constant[0].upcase + constant[1..]
59+
constant.to_sym
60+
end
61+
62+
def set_error_constant(constant) # rubocop:disable Naming/AccessorMethodName
63+
@const_set_mutex.synchronize do
64+
# Ensure the const was not defined while blocked by the mutex
65+
if error_const_set?(constant)
66+
const_get(constant)
67+
else
68+
error_class = Class.new(const_get(:ServiceError))
69+
error_class.code = constant.to_s
70+
const_set(constant, error_class)
71+
end
72+
end
73+
end
74+
75+
def error_const_set?(constant)
76+
# Purposefully not using #const_defined? as that method returns true
77+
# for constants not defined directly in the current module.
78+
constants.include?(constant.to_sym)
79+
end
80+
end
81+
end
82+
end

gems/smithy-client/lib/smithy-client/errors.rb

Lines changed: 0 additions & 150 deletions
This file was deleted.

gems/smithy-client/lib/smithy-client/http/error_inspector.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def client?
6262
end
6363

6464
def modeled_retryable?
65-
@error.is_a?(Errors::ServiceError) && @error.retryable?
65+
@error.is_a?(ServiceError) && @error.retryable?
6666
end
6767

6868
def modeled_throttling?

gems/smithy-client/lib/smithy-client/pageable_output.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
module Smithy
44
module Client
5+
# Raised when calling {PageableOutput#next_page} on a paginator that
6+
# is on the last page of results. You can call {PageableOutput#last_page?}
7+
# or {PageableOutput#next_page?} to know if there are more pages.
8+
class LastPageError < RuntimeError
9+
# @param [Output] output
10+
def initialize(output)
11+
@output = output
12+
super('unable to fetch next page, end of results reached')
13+
end
14+
15+
# @return [Output]
16+
attr_reader :output
17+
end
18+
519
# Decorates a {Smithy::Client::Output} with paging convenience methods.
620
# Most API calls provide paged responses to limit the amount of data returned
721
# with each response. To optimize for latency, some APIs may return an
@@ -75,7 +89,7 @@ def next_page?
7589
# @param [Hash] params A hash of additional request params.
7690
# @return [Output] Returns the next page of results.
7791
def next_page(params = {})
78-
raise Errors::LastPageError, self if last_page?
92+
raise LastPageError, self if last_page?
7993

8094
params = next_page_params(params)
8195
context.client.send(context.operation_name, params)

gems/smithy-client/lib/smithy-client/plugins/sign_requests.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ class SignRequests < Plugin
88
# @api private
99
class Handler < Client::Handler
1010
def call(context)
11-
# TODO: AWS specific - put this in properties
12-
context[:auth].signer_properties['region'] = 'us-west-2'
1311
context[:auth].signer.sign(
1412
request: context.request,
1513
identity: context[:auth].identity,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
module Smithy
4+
module Client
5+
# The base class for all errors returned by a Smithy generated client.
6+
# All ~400 level client errors and ~500 level server errors are raised
7+
# as service errors. This indicates it was an error returned from the
8+
# service and not one generated by the client.
9+
class ServiceError < RuntimeError
10+
# @param [Smithy::Client::HandlerContext] context
11+
# @param [String] message
12+
# @param [Structure] data
13+
def initialize(context, message, data)
14+
@code = self.class.code
15+
@context = context
16+
@message = extract_message(message, data)
17+
@data = data
18+
super(@message)
19+
end
20+
21+
# @return [String, nil] The error code returned by the service.
22+
attr_reader :code
23+
24+
# @return [Smithy::Client::HandlerContext] The context of the request
25+
# that triggered the remote service to return this error.
26+
attr_reader :context
27+
28+
# @return [String] The error message returned by the service.
29+
# Defaults to the class name if no message is provided or can be parsed.
30+
attr_reader :message
31+
32+
# @return [Structure] Additional data returned by the service.
33+
attr_accessor :data
34+
35+
class << self
36+
# @return [String, nil]
37+
attr_accessor :code
38+
end
39+
40+
# @return [Boolean] Returns `true` if the error is retryable.
41+
def retryable?
42+
false
43+
end
44+
45+
# @return [Boolean] Returns `true` if the error is due to throttling.
46+
def throttling?
47+
false
48+
end
49+
50+
private
51+
52+
def extract_message(message, data)
53+
message || (data.message if data.respond_to?(:message)) || self.class.name.to_s
54+
end
55+
end
56+
end
57+
end

gems/smithy-client/sig/smithy-client/errors.rbs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Smithy
2+
module Client
3+
class ServiceError < RuntimeError
4+
def initialize: (HandlerContext?, String?, untyped?) -> void
5+
6+
attr_reader code: String?
7+
attr_reader context: HandlerContext?
8+
attr_reader message: String?
9+
attr_accessor data: untyped?
10+
11+
def self.code: () -> String?
12+
def self.code=: (String) -> void
13+
end
14+
end
15+
end

0 commit comments

Comments
 (0)