treaty 0.1.0 → 0.3.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 +4 -4
- data/README.md +104 -16
- data/config/locales/en.yml +97 -0
- data/lib/treaty/attribute/base.rb +10 -8
- data/lib/treaty/attribute/builder/base.rb +3 -2
- data/lib/treaty/attribute/option/base.rb +1 -0
- data/lib/treaty/attribute/option/modifiers/as_modifier.rb +3 -2
- data/lib/treaty/attribute/option/validators/inclusion_validator.rb +6 -6
- data/lib/treaty/attribute/option/validators/required_validator.rb +2 -4
- data/lib/treaty/attribute/option/validators/type_validator.rb +39 -15
- data/lib/treaty/attribute/option_normalizer.rb +2 -1
- data/lib/treaty/attribute/option_orchestrator.rb +4 -3
- data/lib/treaty/attribute/validation/base.rb +2 -3
- data/lib/treaty/attribute/validation/nested_array_validator.rb +12 -7
- data/lib/treaty/attribute/validation/nested_transformer.rb +13 -7
- data/lib/treaty/attribute/validation/orchestrator/base.rb +2 -4
- data/lib/treaty/controller/dsl.rb +2 -2
- data/lib/treaty/exceptions/base.rb +39 -0
- data/lib/treaty/exceptions/class_name.rb +39 -0
- data/lib/treaty/exceptions/deprecated.rb +46 -0
- data/lib/treaty/exceptions/execution.rb +58 -0
- data/lib/treaty/exceptions/method_name.rb +47 -0
- data/lib/treaty/exceptions/nested_attributes.rb +57 -0
- data/lib/treaty/exceptions/not_implemented.rb +32 -0
- data/lib/treaty/exceptions/strategy.rb +55 -0
- data/lib/treaty/exceptions/unexpected.rb +62 -0
- data/lib/treaty/exceptions/validation.rb +89 -0
- data/lib/treaty/info/builder.rb +3 -3
- data/lib/treaty/request/attribute/attribute.rb +1 -1
- data/lib/treaty/response/attribute/attribute.rb +1 -1
- data/lib/treaty/strategy.rb +2 -2
- data/lib/treaty/version.rb +1 -1
- data/lib/treaty/versions/execution/request.rb +24 -28
- data/lib/treaty/versions/factory.rb +3 -4
- data/lib/treaty/versions/resolver.rb +3 -6
- metadata +21 -5
|
@@ -93,9 +93,8 @@ module Treaty
|
|
|
93
93
|
# @raise [Treaty::Exceptions::Validation] If not implemented
|
|
94
94
|
# @return [Array<ScopeFactory>] Collection of scope factories
|
|
95
95
|
def collection_of_scopes
|
|
96
|
-
# TODO: It is necessary to implement a translation system (I18n).
|
|
97
96
|
raise Treaty::Exceptions::Validation,
|
|
98
|
-
"
|
|
97
|
+
I18n.t("treaty.attributes.validators.nested.orchestrator.collection_not_implemented")
|
|
99
98
|
end
|
|
100
99
|
|
|
101
100
|
# Validates all attributes in a scope (deprecated, not used)
|
|
@@ -139,9 +138,8 @@ module Treaty
|
|
|
139
138
|
# @raise [Treaty::Exceptions::Validation] If not implemented
|
|
140
139
|
# @return [Hash] Scope data
|
|
141
140
|
def scope_data_for(_name)
|
|
142
|
-
# TODO: It is necessary to implement a translation system (I18n).
|
|
143
141
|
raise Treaty::Exceptions::Validation,
|
|
144
|
-
"
|
|
142
|
+
I18n.t("treaty.attributes.validators.nested.orchestrator.scope_data_not_implemented")
|
|
145
143
|
end
|
|
146
144
|
|
|
147
145
|
# Validates and transforms all attributes in a scope
|
|
@@ -24,8 +24,8 @@ module Treaty
|
|
|
24
24
|
def treaty_class
|
|
25
25
|
treaty_class_name.constantize
|
|
26
26
|
rescue NameError
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
raise Treaty::Exceptions::ClassName,
|
|
28
|
+
I18n.t("treaty.controller.treaty_class_not_found", class_name: treaty_class_name)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def treaty_class_name
|
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Base exception class for all Treaty-specific exceptions
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Serves as the parent class for all custom exceptions in the Treaty gem.
|
|
10
|
+
# Allows catching all Treaty-related exceptions with a single rescue clause.
|
|
11
|
+
#
|
|
12
|
+
# ## Usage
|
|
13
|
+
#
|
|
14
|
+
# All Treaty exceptions inherit from this base class:
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# begin
|
|
18
|
+
# Treaty::Base.call!(controller: self, params: params)
|
|
19
|
+
# rescue Treaty::Exceptions::Base => e
|
|
20
|
+
# # Catches any Treaty-specific exception
|
|
21
|
+
# handle_treaty_error(e)
|
|
22
|
+
# end
|
|
23
|
+
# ```
|
|
24
|
+
#
|
|
25
|
+
# ## Integration
|
|
26
|
+
#
|
|
27
|
+
# Can be used in application controllers for centralized error handling:
|
|
28
|
+
#
|
|
29
|
+
# ```ruby
|
|
30
|
+
# rescue_from Treaty::Exceptions::Base, with: :handle_treaty_error
|
|
31
|
+
# ```
|
|
32
|
+
#
|
|
33
|
+
# ## Subclasses
|
|
34
|
+
#
|
|
35
|
+
# - Validation - Attribute validation errors
|
|
36
|
+
# - Execution - Service execution errors
|
|
37
|
+
# - Deprecated - API version deprecation
|
|
38
|
+
# - Strategy - Invalid strategy specification
|
|
39
|
+
# - ClassName - Treaty class not found
|
|
40
|
+
# - MethodName - Unknown method in DSL
|
|
41
|
+
# - NestedAttributes - Nesting depth exceeded
|
|
42
|
+
# - NotImplemented - Abstract method not implemented
|
|
43
|
+
# - Unexpected - General unexpected errors
|
|
5
44
|
class Base < StandardError
|
|
6
45
|
end
|
|
7
46
|
end
|
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when a Treaty class cannot be found or resolved
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Indicates that the system attempted to load a Treaty class (typically via
|
|
10
|
+
# constantize) but the class does not exist in the expected location.
|
|
11
|
+
#
|
|
12
|
+
# ## Usage
|
|
13
|
+
#
|
|
14
|
+
# Raised automatically by the Controller DSL when treaty class resolution fails:
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# # In PostsController, looking for Gate::API::Posts::IndexTreaty
|
|
18
|
+
# def treaty_class
|
|
19
|
+
# treaty_class_name.constantize
|
|
20
|
+
# rescue NameError
|
|
21
|
+
# raise Treaty::Exceptions::ClassName,
|
|
22
|
+
# I18n.t("treaty.controller.treaty_class_not_found", class_name: treaty_class_name)
|
|
23
|
+
# end
|
|
24
|
+
# ```
|
|
25
|
+
#
|
|
26
|
+
# ## Integration
|
|
27
|
+
#
|
|
28
|
+
# Can be rescued by application controllers:
|
|
29
|
+
#
|
|
30
|
+
# ```ruby
|
|
31
|
+
# rescue_from Treaty::Exceptions::ClassName, with: :render_treaty_class_not_found_error
|
|
32
|
+
#
|
|
33
|
+
# def render_treaty_class_not_found_error(exception)
|
|
34
|
+
# render json: { error: exception.message }, status: :internal_server_error
|
|
35
|
+
# end
|
|
36
|
+
# ```
|
|
37
|
+
#
|
|
38
|
+
# ## Common Causes
|
|
39
|
+
#
|
|
40
|
+
# - Treaty class file not created
|
|
41
|
+
# - Incorrect naming convention (should match controller name pattern)
|
|
42
|
+
# - Typo in class name
|
|
43
|
+
# - Missing autoload path configuration
|
|
5
44
|
class ClassName < Base
|
|
6
45
|
def initialize(class_name)
|
|
7
46
|
super("Invalid class name: #{class_name}")
|
|
@@ -2,6 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when attempting to use a deprecated API version
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Prevents usage of API versions that have been marked as deprecated.
|
|
10
|
+
# Helps enforce API version lifecycle management and guides clients
|
|
11
|
+
# to migrate to newer versions.
|
|
12
|
+
#
|
|
13
|
+
# ## Usage
|
|
14
|
+
#
|
|
15
|
+
# Raised automatically during version resolution when a deprecated version is requested:
|
|
16
|
+
#
|
|
17
|
+
# ```ruby
|
|
18
|
+
# version 1 do
|
|
19
|
+
# deprecated true # Simple boolean
|
|
20
|
+
# # or
|
|
21
|
+
# deprecated(ENV['RELEASE_VERSION'].to_i >= 17) # Conditional
|
|
22
|
+
# # or
|
|
23
|
+
# deprecated { some_condition? } # Dynamic evaluation
|
|
24
|
+
#
|
|
25
|
+
# # ... rest of version definition
|
|
26
|
+
# end
|
|
27
|
+
# ```
|
|
28
|
+
#
|
|
29
|
+
# ## Integration
|
|
30
|
+
#
|
|
31
|
+
# Can be rescued by application controllers to return appropriate HTTP status:
|
|
32
|
+
#
|
|
33
|
+
# ```ruby
|
|
34
|
+
# rescue_from Treaty::Exceptions::Deprecated, with: :render_version_deprecated
|
|
35
|
+
#
|
|
36
|
+
# def render_version_deprecated(exception)
|
|
37
|
+
# render json: { error: exception.message }, status: :gone # HTTP 410
|
|
38
|
+
# end
|
|
39
|
+
# ```
|
|
40
|
+
#
|
|
41
|
+
# ## HTTP Status
|
|
42
|
+
#
|
|
43
|
+
# Typically returns HTTP 410 Gone to indicate that the resource (API version)
|
|
44
|
+
# is no longer available and will not be available again.
|
|
45
|
+
#
|
|
46
|
+
# ## Version Lifecycle
|
|
47
|
+
#
|
|
48
|
+
# 1. Version is active (deprecated: false)
|
|
49
|
+
# 2. Version is deprecated (deprecated: true) - raises this exception
|
|
50
|
+
# 3. Version is removed from code
|
|
5
51
|
class Deprecated < Base
|
|
6
52
|
end
|
|
7
53
|
end
|
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when service or executor execution fails
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Indicates errors during the execution phase, including executor resolution,
|
|
10
|
+
# service invocation, and result processing. Wraps underlying errors to provide
|
|
11
|
+
# consistent error handling across different executor types.
|
|
12
|
+
#
|
|
13
|
+
# ## Usage
|
|
14
|
+
#
|
|
15
|
+
# Raised in various execution scenarios:
|
|
16
|
+
#
|
|
17
|
+
# ### Executor Resolution
|
|
18
|
+
# ```ruby
|
|
19
|
+
# # When executor class not found
|
|
20
|
+
# raise Treaty::Exceptions::Execution,
|
|
21
|
+
# I18n.t("treaty.execution.executor_not_found", class_name: "Posts::IndexService")
|
|
22
|
+
#
|
|
23
|
+
# # When executor not defined
|
|
24
|
+
# raise Treaty::Exceptions::Execution,
|
|
25
|
+
# I18n.t("treaty.execution.executor_missing", version: "1.0.0")
|
|
26
|
+
# ```
|
|
27
|
+
#
|
|
28
|
+
# ### Service Execution
|
|
29
|
+
# ```ruby
|
|
30
|
+
# # Proc executor error
|
|
31
|
+
# begin
|
|
32
|
+
# executor.call(params: validated_params)
|
|
33
|
+
# rescue StandardError => e
|
|
34
|
+
# raise Treaty::Exceptions::Execution, I18n.t("treaty.execution.proc_error", message: e.message)
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# # Servactory service error
|
|
38
|
+
# begin
|
|
39
|
+
# executor.call!(params: validated_params)
|
|
40
|
+
# rescue ApplicationService::Exceptions::Input => e
|
|
41
|
+
# raise Treaty::Exceptions::Execution, I18n.t("treaty.execution.servactory_input_error", message: e.message)
|
|
42
|
+
# end
|
|
43
|
+
# ```
|
|
44
|
+
#
|
|
45
|
+
# ## Integration
|
|
46
|
+
#
|
|
47
|
+
# Can be rescued by application controllers:
|
|
48
|
+
#
|
|
49
|
+
# ```ruby
|
|
50
|
+
# rescue_from Treaty::Exceptions::Execution, with: :render_execution_error
|
|
51
|
+
#
|
|
52
|
+
# def render_execution_error(exception)
|
|
53
|
+
# render json: { error: exception.message }, status: :internal_server_error
|
|
54
|
+
# end
|
|
55
|
+
# ```
|
|
56
|
+
#
|
|
57
|
+
# ## Executor Types
|
|
58
|
+
#
|
|
59
|
+
# Handles errors from multiple executor types:
|
|
60
|
+
# - Proc - Lambda/Proc executors
|
|
61
|
+
# - Servactory - ApplicationService-based services
|
|
62
|
+
# - Regular Class - Plain Ruby classes with custom methods
|
|
5
63
|
class Execution < Base
|
|
6
64
|
end
|
|
7
65
|
end
|
|
@@ -2,6 +2,53 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when an unknown method is called in the version DSL
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Prevents typos and invalid method calls in the treaty version definition DSL.
|
|
10
|
+
# Ensures only recognized DSL methods are used within version blocks.
|
|
11
|
+
#
|
|
12
|
+
# ## Usage
|
|
13
|
+
#
|
|
14
|
+
# Raised automatically by method_missing in VersionFactory:
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# version 1 do
|
|
18
|
+
# strategy Treaty::Strategy::ADAPTER # Valid
|
|
19
|
+
# deprecated true # Valid
|
|
20
|
+
# summary "Version 1" # Valid
|
|
21
|
+
#
|
|
22
|
+
# invalid_method "foo" # Raises Treaty::Exceptions::MethodName
|
|
23
|
+
# end
|
|
24
|
+
# ```
|
|
25
|
+
#
|
|
26
|
+
# ## Integration
|
|
27
|
+
#
|
|
28
|
+
# Typically caught during development/testing rather than production:
|
|
29
|
+
#
|
|
30
|
+
# ```ruby
|
|
31
|
+
# rescue_from Treaty::Exceptions::MethodName, with: :render_dsl_error
|
|
32
|
+
#
|
|
33
|
+
# def render_dsl_error(exception)
|
|
34
|
+
# render json: { error: exception.message }, status: :internal_server_error
|
|
35
|
+
# end
|
|
36
|
+
# ```
|
|
37
|
+
#
|
|
38
|
+
# ## Valid DSL Methods
|
|
39
|
+
#
|
|
40
|
+
# Within a version block, these methods are valid:
|
|
41
|
+
# - strategy(code) - Set version strategy (DIRECT/ADAPTER)
|
|
42
|
+
# - deprecated(condition) - Mark version as deprecated
|
|
43
|
+
# - summary(text) - Add version description
|
|
44
|
+
# - request(&block) - Define request schema
|
|
45
|
+
# - response(status, &block) - Define response schema
|
|
46
|
+
# - delegate_to(executor, method) - Set executor
|
|
47
|
+
#
|
|
48
|
+
# ## Prevention
|
|
49
|
+
#
|
|
50
|
+
# Always refer to Treaty documentation for valid DSL methods.
|
|
51
|
+
# This exception helps catch typos early in development.
|
|
5
52
|
class MethodName < Base
|
|
6
53
|
end
|
|
7
54
|
end
|
|
@@ -2,6 +2,63 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when attribute nesting depth exceeds configured maximum
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Prevents excessive nesting of attributes which can lead to:
|
|
10
|
+
# - Performance degradation
|
|
11
|
+
# - Complex validation logic
|
|
12
|
+
# - Difficult to maintain code
|
|
13
|
+
# - Stack overflow risks
|
|
14
|
+
#
|
|
15
|
+
# ## Usage
|
|
16
|
+
#
|
|
17
|
+
# Raised automatically when defining deeply nested attributes:
|
|
18
|
+
#
|
|
19
|
+
# ```ruby
|
|
20
|
+
# request do
|
|
21
|
+
# scope :user do
|
|
22
|
+
# object :profile do
|
|
23
|
+
# object :settings do
|
|
24
|
+
# object :preferences do
|
|
25
|
+
# object :notifications do
|
|
26
|
+
# # If max nesting is 3, this raises NestedAttributes exception
|
|
27
|
+
# string :email_enabled
|
|
28
|
+
# end
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
# ```
|
|
35
|
+
#
|
|
36
|
+
# ## Configuration
|
|
37
|
+
#
|
|
38
|
+
# Maximum nesting level is configurable in Treaty engine configuration:
|
|
39
|
+
#
|
|
40
|
+
# ```ruby
|
|
41
|
+
# Treaty::Engine.config.treaty.attribute_nesting_level = 3 # Default
|
|
42
|
+
# ```
|
|
43
|
+
#
|
|
44
|
+
# ## Integration
|
|
45
|
+
#
|
|
46
|
+
# Can be rescued by application controllers:
|
|
47
|
+
#
|
|
48
|
+
# ```ruby
|
|
49
|
+
# rescue_from Treaty::Exceptions::NestedAttributes, with: :render_nesting_error
|
|
50
|
+
#
|
|
51
|
+
# def render_nesting_error(exception)
|
|
52
|
+
# render json: { error: exception.message }, status: :unprocessable_entity
|
|
53
|
+
# end
|
|
54
|
+
# ```
|
|
55
|
+
#
|
|
56
|
+
# ## Best Practices
|
|
57
|
+
#
|
|
58
|
+
# - Keep nesting shallow (2-3 levels maximum)
|
|
59
|
+
# - Consider flattening deeply nested structures
|
|
60
|
+
# - Use separate scopes instead of deep nesting
|
|
61
|
+
# - Refactor complex structures into simpler ones
|
|
5
62
|
class NestedAttributes < Base
|
|
6
63
|
end
|
|
7
64
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Exceptions
|
|
5
|
+
class NotImplemented < Base
|
|
6
|
+
# Custom NotImplementedError for Treaty
|
|
7
|
+
#
|
|
8
|
+
# ## Purpose
|
|
9
|
+
#
|
|
10
|
+
# Indicates that a required method must be implemented in a subclass.
|
|
11
|
+
# Used instead of Ruby's standard NotImplementedError to integrate with
|
|
12
|
+
# Treaty's exception handling system.
|
|
13
|
+
#
|
|
14
|
+
# ## Usage
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# def some_method
|
|
18
|
+
# raise Treaty::Exceptions::NotImplemented,
|
|
19
|
+
# I18n.t("treaty.attributes.builder.not_implemented", class: self.class)
|
|
20
|
+
# end
|
|
21
|
+
# ```
|
|
22
|
+
#
|
|
23
|
+
# ## Integration
|
|
24
|
+
#
|
|
25
|
+
# Can be rescued by application controllers using rescue_from:
|
|
26
|
+
#
|
|
27
|
+
# ```ruby
|
|
28
|
+
# rescue_from Treaty::Exceptions::NotImplemented, with: :render_not_implemented_error
|
|
29
|
+
# ```
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -2,6 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when an unknown or invalid strategy is specified
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Ensures only valid strategy types are used in version definitions.
|
|
10
|
+
# Prevents typos and invalid strategy configurations.
|
|
11
|
+
#
|
|
12
|
+
# ## Usage
|
|
13
|
+
#
|
|
14
|
+
# Raised when specifying an invalid strategy in version definition:
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# version 1 do
|
|
18
|
+
# strategy Treaty::Strategy::ADAPTER # Valid
|
|
19
|
+
# strategy Treaty::Strategy::DIRECT # Valid
|
|
20
|
+
#
|
|
21
|
+
# strategy :invalid_strategy # Raises Treaty::Exceptions::Strategy
|
|
22
|
+
# end
|
|
23
|
+
# ```
|
|
24
|
+
#
|
|
25
|
+
# ## Valid Strategies
|
|
26
|
+
#
|
|
27
|
+
# Only two strategies are supported:
|
|
28
|
+
#
|
|
29
|
+
# - `Treaty::Strategy::DIRECT` - Direct pass-through mode
|
|
30
|
+
# - No transformation between service and response
|
|
31
|
+
# - Service output becomes response output directly
|
|
32
|
+
# - Faster but less flexible
|
|
33
|
+
#
|
|
34
|
+
# - `Treaty::Strategy::ADAPTER` - Adapter mode (default)
|
|
35
|
+
# - Transforms service output to match response schema
|
|
36
|
+
# - Validates and adapts data structure
|
|
37
|
+
# - More flexible, recommended for most cases
|
|
38
|
+
#
|
|
39
|
+
# ## Integration
|
|
40
|
+
#
|
|
41
|
+
# Can be rescued by application controllers:
|
|
42
|
+
#
|
|
43
|
+
# ```ruby
|
|
44
|
+
# rescue_from Treaty::Exceptions::Strategy, with: :render_strategy_error
|
|
45
|
+
#
|
|
46
|
+
# def render_strategy_error(exception)
|
|
47
|
+
# render json: { error: exception.message }, status: :internal_server_error
|
|
48
|
+
# end
|
|
49
|
+
# ```
|
|
50
|
+
#
|
|
51
|
+
# ## Default Behavior
|
|
52
|
+
#
|
|
53
|
+
# If no strategy is specified, ADAPTER is used by default:
|
|
54
|
+
#
|
|
55
|
+
# ```ruby
|
|
56
|
+
# version 1 do
|
|
57
|
+
# # strategy defaults to Treaty::Strategy::ADAPTER
|
|
58
|
+
# end
|
|
59
|
+
# ```
|
|
5
60
|
class Strategy < Base
|
|
6
61
|
end
|
|
7
62
|
end
|
|
@@ -2,6 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised for unexpected errors that don't fit other exception types
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Serves as a catch-all for unexpected errors that occur during Treaty
|
|
10
|
+
# processing but don't fall into specific exception categories.
|
|
11
|
+
# Helps maintain consistent error handling across the gem.
|
|
12
|
+
#
|
|
13
|
+
# ## Usage
|
|
14
|
+
#
|
|
15
|
+
# Used for rare or unexpected edge cases:
|
|
16
|
+
#
|
|
17
|
+
# ```ruby
|
|
18
|
+
# def process_data(data)
|
|
19
|
+
# # ... processing logic
|
|
20
|
+
# rescue => e
|
|
21
|
+
# # Log the unexpected error for investigation
|
|
22
|
+
# Rails.logger.error("Unexpected Treaty error: #{e.message}")
|
|
23
|
+
#
|
|
24
|
+
# raise Treaty::Exceptions::Unexpected,
|
|
25
|
+
# "An unexpected error occurred during processing: #{e.message}"
|
|
26
|
+
# end
|
|
27
|
+
# ```
|
|
28
|
+
#
|
|
29
|
+
# ## Integration
|
|
30
|
+
#
|
|
31
|
+
# Can be rescued by application controllers as a safety net:
|
|
32
|
+
#
|
|
33
|
+
# ```ruby
|
|
34
|
+
# rescue_from Treaty::Exceptions::Unexpected, with: :render_unexpected_error
|
|
35
|
+
#
|
|
36
|
+
# def render_unexpected_error(exception)
|
|
37
|
+
# # Log for investigation
|
|
38
|
+
# Rails.logger.error("Unexpected Treaty exception: #{exception.message}")
|
|
39
|
+
# Rails.logger.error(exception.backtrace.join("\n"))
|
|
40
|
+
#
|
|
41
|
+
# render json: { error: "An unexpected error occurred" },
|
|
42
|
+
# status: :internal_server_error
|
|
43
|
+
# end
|
|
44
|
+
# ```
|
|
45
|
+
#
|
|
46
|
+
# ## When to Use
|
|
47
|
+
#
|
|
48
|
+
# - Edge cases not covered by specific exceptions
|
|
49
|
+
# - Defensive programming for "should never happen" scenarios
|
|
50
|
+
# - Wrapping third-party library errors
|
|
51
|
+
# - Temporary exception during development before creating specific type
|
|
52
|
+
#
|
|
53
|
+
# ## When Not to Use
|
|
54
|
+
#
|
|
55
|
+
# If the error fits an existing exception type, use that instead:
|
|
56
|
+
# - Validation errors → Treaty::Exceptions::Validation
|
|
57
|
+
# - Execution errors → Treaty::Exceptions::Execution
|
|
58
|
+
# - Configuration errors → specific exception type
|
|
59
|
+
#
|
|
60
|
+
# ## Investigation
|
|
61
|
+
#
|
|
62
|
+
# When this exception occurs in production:
|
|
63
|
+
# 1. Review logs for full context
|
|
64
|
+
# 2. Analyze stack trace
|
|
65
|
+
# 3. Consider creating a specific exception type if pattern emerges
|
|
66
|
+
# 4. Add tests to prevent recurrence
|
|
5
67
|
class Unexpected < Base
|
|
6
68
|
end
|
|
7
69
|
end
|
|
@@ -2,6 +2,95 @@
|
|
|
2
2
|
|
|
3
3
|
module Treaty
|
|
4
4
|
module Exceptions
|
|
5
|
+
# Raised when attribute validation fails
|
|
6
|
+
#
|
|
7
|
+
# ## Purpose
|
|
8
|
+
#
|
|
9
|
+
# Indicates that data does not conform to the schema defined in the treaty.
|
|
10
|
+
# Most commonly used exception in Treaty, covering all validation scenarios
|
|
11
|
+
# including type mismatches, required fields, inclusion constraints, and more.
|
|
12
|
+
#
|
|
13
|
+
# ## Usage
|
|
14
|
+
#
|
|
15
|
+
# Raised automatically during validation in various scenarios:
|
|
16
|
+
#
|
|
17
|
+
# ### Required Field Validation
|
|
18
|
+
# ```ruby
|
|
19
|
+
# request do
|
|
20
|
+
# string :title, :required
|
|
21
|
+
# end
|
|
22
|
+
# # Raises: "Attribute 'title' is required but was not provided or is empty"
|
|
23
|
+
# ```
|
|
24
|
+
#
|
|
25
|
+
# ### Type Validation
|
|
26
|
+
# ```ruby
|
|
27
|
+
# request do
|
|
28
|
+
# integer :age
|
|
29
|
+
# end
|
|
30
|
+
# # Passing "25" as string raises:
|
|
31
|
+
# # "Attribute 'age' must be an Integer, got String"
|
|
32
|
+
# ```
|
|
33
|
+
#
|
|
34
|
+
# ### Inclusion Validation
|
|
35
|
+
# ```ruby
|
|
36
|
+
# request do
|
|
37
|
+
# string :status, inclusion: ["active", "inactive"]
|
|
38
|
+
# end
|
|
39
|
+
# # Passing "pending" raises:
|
|
40
|
+
# # "Attribute 'status' must be one of: active, inactive. Got: 'pending'"
|
|
41
|
+
# ```
|
|
42
|
+
#
|
|
43
|
+
# ### Nested Structure Validation
|
|
44
|
+
# ```ruby
|
|
45
|
+
# request do
|
|
46
|
+
# array :tags do
|
|
47
|
+
# string :_self
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
# # Passing [123, 456] raises:
|
|
51
|
+
# # "Error in array 'tags' at index 0: Element must match one of the defined types"
|
|
52
|
+
# ```
|
|
53
|
+
#
|
|
54
|
+
# ### Custom Messages
|
|
55
|
+
# ```ruby
|
|
56
|
+
# request do
|
|
57
|
+
# string :email, required: { is: true, message: "Email is mandatory for registration" }
|
|
58
|
+
# end
|
|
59
|
+
# # Raises custom message when email is missing
|
|
60
|
+
# ```
|
|
61
|
+
#
|
|
62
|
+
# ## Integration
|
|
63
|
+
#
|
|
64
|
+
# Can be rescued by application controllers to return appropriate HTTP status:
|
|
65
|
+
#
|
|
66
|
+
# ```ruby
|
|
67
|
+
# rescue_from Treaty::Exceptions::Validation, with: :render_validation_error
|
|
68
|
+
#
|
|
69
|
+
# def render_validation_error(exception)
|
|
70
|
+
# render json: { error: exception.message }, status: :unprocessable_entity # HTTP 422
|
|
71
|
+
# end
|
|
72
|
+
# ```
|
|
73
|
+
#
|
|
74
|
+
# ## Validation Types
|
|
75
|
+
#
|
|
76
|
+
# This exception covers multiple validation scenarios:
|
|
77
|
+
#
|
|
78
|
+
# - **Required** - Attribute presence validation
|
|
79
|
+
# - **Type** - Data type validation (integer, string, array, object, datetime)
|
|
80
|
+
# - **Inclusion** - Value must be in allowed set
|
|
81
|
+
# - **Nested** - Complex structure validation (arrays, objects)
|
|
82
|
+
# - **Options** - Unknown or invalid option specifications
|
|
83
|
+
# - **Schema** - DSL definition validation
|
|
84
|
+
#
|
|
85
|
+
# ## HTTP Status
|
|
86
|
+
#
|
|
87
|
+
# Typically returns HTTP 422 Unprocessable Entity, indicating that the
|
|
88
|
+
# request was well-formed but contains semantic errors.
|
|
89
|
+
#
|
|
90
|
+
# ## Localization
|
|
91
|
+
#
|
|
92
|
+
# All validation messages support I18n for multilingual applications.
|
|
93
|
+
# Messages are defined in `config/locales/en.yml` under `treaty.attributes.validators.*`.
|
|
5
94
|
class Validation < Base
|
|
6
95
|
end
|
|
7
96
|
end
|
data/lib/treaty/info/builder.rb
CHANGED
|
@@ -112,10 +112,10 @@ module Treaty
|
|
|
112
112
|
# def validate_nesting_level!(level)
|
|
113
113
|
# return unless level > Treaty::Engine.config.treaty.attribute_nesting_level
|
|
114
114
|
#
|
|
115
|
-
# # TODO: It is necessary to implement a translation system (I18n).
|
|
116
115
|
# raise Treaty::Exceptions::NestedAttributes,
|
|
117
|
-
# "
|
|
118
|
-
#
|
|
116
|
+
# I18n.t("treaty.attributes.errors.nesting_level_exceeded",
|
|
117
|
+
# level:,
|
|
118
|
+
# max_level: Treaty::Engine.config.treaty.attribute_nesting_level)
|
|
119
119
|
# end
|
|
120
120
|
end
|
|
121
121
|
end
|
|
@@ -8,7 +8,7 @@ module Treaty
|
|
|
8
8
|
|
|
9
9
|
def apply_defaults!
|
|
10
10
|
# For request: required by default (true).
|
|
11
|
-
#
|
|
11
|
+
# message: nil means use I18n default message from validators
|
|
12
12
|
@options[:required] ||= { is: true, message: nil }
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@ module Treaty
|
|
|
8
8
|
|
|
9
9
|
def apply_defaults!
|
|
10
10
|
# For response: optional by default (false).
|
|
11
|
-
#
|
|
11
|
+
# message: nil means use I18n default message from validators
|
|
12
12
|
@options[:required] ||= { is: false, message: nil }
|
|
13
13
|
end
|
|
14
14
|
|
data/lib/treaty/strategy.rb
CHANGED
|
@@ -16,8 +16,8 @@ module Treaty
|
|
|
16
16
|
def validate!
|
|
17
17
|
return self if LIST.include?(@code)
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
raise Treaty::Exceptions::Strategy,
|
|
20
|
+
I18n.t("treaty.versioning.strategy.unknown", strategy: @code)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def direct?
|