treaty 0.9.0 → 0.10.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
  SHA256:
3
- metadata.gz: 8fd8fd4a097f7ff97cdb53e0d7825d79da5562d0bb6347e8e40794c158f8cb41
4
- data.tar.gz: b0e119a2ba1018b4eeeb49c753b2949fb4c320ca89be29d633e7e6367cbd7360
3
+ metadata.gz: f3115e472c191d30a9c5c8bea6bceb1ed6674437c4e82053817da35e4e94ed4f
4
+ data.tar.gz: e43b55d9b75c5d2ded71686319a773a814863c10e7d6c25a030151d45883ceeb
5
5
  SHA512:
6
- metadata.gz: 10514553e41066a04e066e6561744f69ca779bc4a87594bab7dce48b7e6217a5d5a6f2b7e28f1770876a9d3ff82d2f715cf4d167ef683dc36723b65a1549dc62
7
- data.tar.gz: e262a6a4b2dbe068c53ced57ddcd7d9687a8e0be7d13f90ab8c2b9176015a3099829af702f59d22d28588a8c929e7178746d79356c35d4d0e899cc46991ce439
6
+ metadata.gz: f83bdae2ce72bb4f47773ccfa3911be30fb55a5710d211778ce725d487a6b09044c838d18fa23299607ae2ade4cbe671a189ed7d0969b57f1ab7ceaf912c8680
7
+ data.tar.gz: 01b3769426d4b04b1fe18441c3d943aa36ad8ccca077e7f0d4bf7c5ab1179ec88ae3343c4cd09a9274a87bcf97a88707479458bf7f9fc64fac6936770f0fce06
data/README.md CHANGED
@@ -13,18 +13,18 @@
13
13
  </div>
14
14
 
15
15
  > [!WARNING]
16
- > **Development Status**: Treaty is currently under active development in the 0.x version series. Breaking changes may occur between minor versions (0.x) as we refine the API and add new features. The library will stabilize with the 1.0 release. We recommend pinning to specific patch versions in your Gemfile (e.g., `gem "treaty", "~> 0.5.0"`) until the 1.0 release.
16
+ > **Development Status**: Treaty is currently under active development in the 0.x version series. Breaking changes may occur between minor versions (0.x) as we refine the API and add new features. The library will stabilize with the 1.0 release. We recommend pinning to specific patch versions in your Gemfile (e.g., `gem "treaty", "~> 0.9.0"`) until the 1.0 release.
17
17
 
18
18
  ## 📚 Documentation
19
19
 
20
20
  Explore comprehensive guides and documentation at [docs](./docs):
21
21
 
22
- - [Getting Started](./docs/getting-started.md) - installation and configuration
23
- - [Core Concepts](./docs/core-concepts.md) - understand fundamental concepts
24
- - [API Reference](./docs/api-reference.md) - complete API documentation
25
- - [Examples](./docs/examples.md) - practical real-world examples
22
+ - [Getting Started](./docs/getting-started.md) - Installation and basic setup
23
+ - [Core Concepts](./docs/core-concepts.md) - Fundamental concepts and architecture
24
+ - [API Reference](./docs/api-reference.md) - Complete API documentation
25
+ - [Examples](./docs/examples.md) - Real-world usage examples
26
26
  - [Internationalization](./docs/internationalization.md) - I18n and multilingual support
27
- - [Full Documentation Index](./docs/README.md) - all documentation topics
27
+ - [Full Documentation Index](./docs/README.md) - Complete documentation index
28
28
 
29
29
  ## 💡 Why Treaty?
30
30
 
@@ -84,7 +84,7 @@ en:
84
84
  versioning:
85
85
  # Version resolver
86
86
  resolver:
87
- current_version_required: "Current version is required for validation"
87
+ specified_version_required: "Specified version is required for validation"
88
88
  version_not_found: "Version %{version} not found in treaty definition"
89
89
  version_deprecated: "Version %{version} is deprecated and cannot be used"
90
90
 
@@ -35,6 +35,8 @@ module Treaty
35
35
  # - Validation - Attribute validation errors
36
36
  # - Execution - Service execution errors
37
37
  # - Deprecated - API version deprecation
38
+ # - SpecifiedVersionNotFound - No version specified and no default configured
39
+ # - VersionNotFound - Requested version doesn't exist
38
40
  # - Strategy - Invalid strategy specification
39
41
  # - ClassName - Treaty class not found
40
42
  # - MethodName - Unknown method in DSL
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Exceptions
5
+ # Raised when no API version is specified and no default version is configured
6
+ #
7
+ # ## Purpose
8
+ #
9
+ # Prevents treaty execution when the client doesn't specify a version
10
+ # and the treaty hasn't defined a default version to fall back to.
11
+ # Enforces explicit version selection for API contracts.
12
+ #
13
+ # ## Usage
14
+ #
15
+ # Raised automatically during version resolution in two scenarios:
16
+ #
17
+ # ### Scenario 1: No Version Specified, No Default Configured
18
+ # ```ruby
19
+ # class PostsTreaty < ApplicationTreaty
20
+ # version 1 do
21
+ # # No default: true specified
22
+ # request { string :title }
23
+ # response(200) { object :post }
24
+ # end
25
+ #
26
+ # version 2 do
27
+ # request { string :title }
28
+ # response(200) { object :post }
29
+ # end
30
+ # end
31
+ #
32
+ # # Client request without version header
33
+ # PostsTreaty.call!(version: nil, params: { title: "Test" })
34
+ # # => Raises Treaty::Exceptions::SpecifiedVersionNotFound
35
+ # # => "Specified version is required for validation"
36
+ # ```
37
+ #
38
+ # ### Scenario 2: Empty Version String
39
+ # ```ruby
40
+ # PostsTreaty.call!(version: "", params: { title: "Test" })
41
+ # # => Raises Treaty::Exceptions::SpecifiedVersionNotFound
42
+ # ```
43
+ #
44
+ # ### Prevention: Define Default Version
45
+ # ```ruby
46
+ # class PostsTreaty < ApplicationTreaty
47
+ # version 1 do
48
+ # request { string :title }
49
+ # response(200) { object :post }
50
+ # end
51
+ #
52
+ # version 2, default: true do # Marks version 2 as default
53
+ # request { string :title }
54
+ # response(200) { object :post }
55
+ # end
56
+ # end
57
+ #
58
+ # # Now works without explicit version
59
+ # PostsTreaty.call!(version: nil, params: { title: "Test" })
60
+ # # => Uses version 2 by default
61
+ # ```
62
+ #
63
+ # ## Integration
64
+ #
65
+ # Can be rescued by application controllers to return appropriate HTTP status:
66
+ #
67
+ # ```ruby
68
+ # rescue_from Treaty::Exceptions::SpecifiedVersionNotFound, with: :render_version_required
69
+ #
70
+ # def render_version_required(exception)
71
+ # render json: {
72
+ # error: exception.message,
73
+ # hint: "Please specify an API version in the request header"
74
+ # }, status: :bad_request # HTTP 400
75
+ # end
76
+ # ```
77
+ #
78
+ # ## HTTP Status
79
+ #
80
+ # Typically returns HTTP 400 Bad Request, indicating that the client
81
+ # failed to provide required version information.
82
+ #
83
+ # ## Best Practices
84
+ #
85
+ # ### For API Providers
86
+ #
87
+ # 1. **Always define a default version** for backward compatibility:
88
+ # ```ruby
89
+ # version 1, default: true do
90
+ # # ...
91
+ # end
92
+ # ```
93
+ #
94
+ # 2. **Document version requirements** in API documentation
95
+ #
96
+ # 3. **Provide helpful error messages** in rescue handlers
97
+ #
98
+ # ### For API Clients
99
+ #
100
+ # 1. **Always specify version explicitly** in production code
101
+ # 2. **Don't rely on default versions** for critical applications
102
+ # 3. **Handle this exception** with version selection logic
103
+ #
104
+ # ## Difference from VersionNotFound
105
+ #
106
+ # - **SpecifiedVersionNotFound**: No version specified (nil/blank)
107
+ # - **VersionNotFound**: Specific version specified but doesn't exist
108
+ #
109
+ # ## Version Selection Flow
110
+ #
111
+ # 1. Client provides version → Use specified version
112
+ # 2. Client provides no version → Look for default version
113
+ # 3. No default version configured → Raise SpecifiedVersionNotFound
114
+ class SpecifiedVersionNotFound < Base
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Exceptions
5
+ # Raised when a specific API version is requested but doesn't exist in the treaty
6
+ #
7
+ # ## Purpose
8
+ #
9
+ # Prevents execution with non-existent API versions. Helps clients
10
+ # discover available versions and prevents errors from version mismatches.
11
+ # Ensures API versioning integrity.
12
+ #
13
+ # ## Usage
14
+ #
15
+ # Raised automatically during version resolution when a requested version
16
+ # is not defined in the treaty:
17
+ #
18
+ # ### Example: Requesting Non-Existent Version
19
+ # ```ruby
20
+ # class PostsTreaty < ApplicationTreaty
21
+ # version 1 do
22
+ # request { string :title }
23
+ # response(200) { object :post }
24
+ # end
25
+ #
26
+ # version 2, default: true do
27
+ # request { string :title, :summary }
28
+ # response(200) { object :post }
29
+ # end
30
+ # end
31
+ #
32
+ # # Client requests version 3 (doesn't exist)
33
+ # PostsTreaty.call!(version: "3", params: { title: "Test" })
34
+ # # => Raises Treaty::Exceptions::VersionNotFound
35
+ # # => "Version 3 not found in treaty definition"
36
+ # ```
37
+ #
38
+ # ### Example: Version Format Mismatch
39
+ # ```ruby
40
+ # # Treaty defines version 1
41
+ # version 1 do
42
+ # # ...
43
+ # end
44
+ #
45
+ # # Client requests "1.0.0" (treated as different from "1")
46
+ # PostsTreaty.call!(version: "1.0.0", params: {})
47
+ # # => Raises Treaty::Exceptions::VersionNotFound if exact match not found
48
+ # ```
49
+ #
50
+ # ### Example: Typo in Version Number
51
+ # ```ruby
52
+ # PostsTreaty.call!(version: "v2", params: {}) # Should be "2"
53
+ # # => Raises Treaty::Exceptions::VersionNotFound
54
+ # ```
55
+ #
56
+ # ## Integration
57
+ #
58
+ # Can be rescued by application controllers to return appropriate HTTP status:
59
+ #
60
+ # ```ruby
61
+ # rescue_from Treaty::Exceptions::VersionNotFound, with: :render_version_not_found
62
+ #
63
+ # def render_version_not_found(exception)
64
+ # available_versions = extract_available_versions(exception)
65
+ #
66
+ # render json: {
67
+ # error: exception.message,
68
+ # available_versions: available_versions,
69
+ # hint: "Please use one of the available API versions"
70
+ # }, status: :not_found # HTTP 404
71
+ # end
72
+ # ```
73
+ #
74
+ # ## HTTP Status
75
+ #
76
+ # Typically returns HTTP 404 Not Found, indicating that the requested
77
+ # resource (API version) does not exist on the server.
78
+ #
79
+ # ## Common Scenarios
80
+ #
81
+ # ### 1. Client Using Outdated Version Number
82
+ # ```ruby
83
+ # # Version 1 was removed, only version 2 and 3 exist
84
+ # PostsTreaty.call!(version: "1", params: {})
85
+ # # => VersionNotFound
86
+ # ```
87
+ #
88
+ # ### 2. Client Using Future Version
89
+ # ```ruby
90
+ # # Client expects version 5 but only version 1-3 deployed
91
+ # PostsTreaty.call!(version: "5", params: {})
92
+ # # => VersionNotFound
93
+ # ```
94
+ #
95
+ # ### 3. Version Format Inconsistency
96
+ # ```ruby
97
+ # # Treaty uses integers, client uses semantic versioning
98
+ # version 1 do ... end
99
+ # version 2 do ... end
100
+ #
101
+ # PostsTreaty.call!(version: "v2.0.0", params: {})
102
+ # # => VersionNotFound (should use "2")
103
+ # ```
104
+ #
105
+ # ## Best Practices
106
+ #
107
+ # ### For API Providers
108
+ #
109
+ # 1. **Version numbering consistency**:
110
+ # ```ruby
111
+ # # Choose one format and stick with it
112
+ # version 1 do ... end
113
+ # version 2 do ... end
114
+ # # OR
115
+ # version "1.0.0" do ... end
116
+ # version "2.0.0" do ... end
117
+ # ```
118
+ #
119
+ # 2. **Document available versions** in API documentation
120
+ #
121
+ # 3. **Provide version discovery endpoint**:
122
+ # ```ruby
123
+ # GET /api/versions
124
+ # # => { available_versions: ["1", "2", "3"], default: "3" }
125
+ # ```
126
+ #
127
+ # 4. **Use deprecation** before removal:
128
+ # ```ruby
129
+ # version 1 do
130
+ # deprecated true # Warn before removing
131
+ # end
132
+ # ```
133
+ #
134
+ # ### For API Clients
135
+ #
136
+ # 1. **Validate version before requests**
137
+ # 2. **Handle version errors gracefully**
138
+ # 3. **Check API documentation** for available versions
139
+ # 4. **Implement version fallback logic** when appropriate
140
+ #
141
+ # ## Difference from SpecifiedVersionNotFound
142
+ #
143
+ # - **SpecifiedVersionNotFound**: No version specified (nil/blank), no default configured
144
+ # - **VersionNotFound**: Specific version specified but doesn't exist in treaty
145
+ #
146
+ # ## Difference from Deprecated
147
+ #
148
+ # - **VersionNotFound**: Version doesn't exist at all (HTTP 404)
149
+ # - **Deprecated**: Version exists but is marked as deprecated (HTTP 410)
150
+ #
151
+ # ## Version Resolution Order
152
+ #
153
+ # 1. Version specified → Look for exact match
154
+ # 2. Exact match not found → Raise VersionNotFound
155
+ # 3. Match found but deprecated → Raise Deprecated
156
+ # 4. Match found and active → Use version
157
+ class VersionNotFound < Base
158
+ end
159
+ end
160
+ end
@@ -3,7 +3,7 @@
3
3
  module Treaty
4
4
  module VERSION
5
5
  MAJOR = 0
6
- MINOR = 9
6
+ MINOR = 10
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
@@ -7,15 +7,15 @@ module Treaty
7
7
  new(...).resolve!
8
8
  end
9
9
 
10
- def initialize(current_version:, collection_of_versions:)
11
- @current_version = current_version
10
+ def initialize(specified_version:, collection_of_versions:)
11
+ @specified_version = specified_version
12
12
  @collection_of_versions = collection_of_versions
13
13
  end
14
14
 
15
15
  def resolve!
16
16
  determined_factory =
17
- if current_version_blank?
18
- default_version_factory || raise_current_version_not_found!
17
+ if specified_version_blank?
18
+ default_version_factory || raise_specified_version_not_found!
19
19
  else
20
20
  version_factory || raise_version_not_found!
21
21
  end
@@ -30,7 +30,7 @@ module Treaty
30
30
  def version_factory
31
31
  @version_factory ||=
32
32
  @collection_of_versions.find do |factory|
33
- factory.version.version == @current_version
33
+ factory.version.version == @specified_version
34
34
  end
35
35
  end
36
36
 
@@ -39,22 +39,22 @@ module Treaty
39
39
  @collection_of_versions.find(&:default_result)
40
40
  end
41
41
 
42
- def current_version_blank?
43
- @current_version.to_s.strip.empty?
42
+ def specified_version_blank?
43
+ @specified_version.to_s.strip.empty?
44
44
  end
45
45
 
46
46
  ##########################################################################
47
47
 
48
- def raise_current_version_not_found!
49
- raise Treaty::Exceptions::Validation,
50
- I18n.t("treaty.versioning.resolver.current_version_required")
48
+ def raise_specified_version_not_found!
49
+ raise Treaty::Exceptions::SpecifiedVersionNotFound,
50
+ I18n.t("treaty.versioning.resolver.specified_version_required")
51
51
  end
52
52
 
53
53
  def raise_version_not_found!
54
- raise Treaty::Exceptions::Validation,
54
+ raise Treaty::Exceptions::VersionNotFound,
55
55
  I18n.t(
56
56
  "treaty.versioning.resolver.version_not_found",
57
- version: @current_version
57
+ version: @specified_version
58
58
  )
59
59
  end
60
60
 
@@ -62,7 +62,7 @@ module Treaty
62
62
  raise Treaty::Exceptions::Deprecated,
63
63
  I18n.t(
64
64
  "treaty.versioning.resolver.version_deprecated",
65
- version: @current_version
65
+ version: @specified_version
66
66
  )
67
67
  end
68
68
  end
@@ -9,7 +9,7 @@ module Treaty
9
9
  super
10
10
 
11
11
  version_factory = Resolver.resolve!(
12
- current_version: version,
12
+ specified_version: version,
13
13
  collection_of_versions: @collection_of_versions
14
14
  )
15
15
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: treaty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
@@ -186,9 +186,11 @@ files:
186
186
  - lib/treaty/exceptions/method_name.rb
187
187
  - lib/treaty/exceptions/nested_attributes.rb
188
188
  - lib/treaty/exceptions/not_implemented.rb
189
+ - lib/treaty/exceptions/specified_version_not_found.rb
189
190
  - lib/treaty/exceptions/strategy.rb
190
191
  - lib/treaty/exceptions/unexpected.rb
191
192
  - lib/treaty/exceptions/validation.rb
193
+ - lib/treaty/exceptions/version_not_found.rb
192
194
  - lib/treaty/info/entity/builder.rb
193
195
  - lib/treaty/info/entity/dsl.rb
194
196
  - lib/treaty/info/entity/result.rb