apicraft-rails 0.5.1.beta1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +54 -19
- data/lib/apicraft/concerns/middleware_util.rb +18 -0
- data/lib/apicraft/concerns.rb +1 -0
- data/lib/apicraft/config.rb +37 -7
- data/lib/apicraft/errors.rb +1 -0
- data/lib/apicraft/middlewares/introspector.rb +2 -4
- data/lib/apicraft/middlewares/mocker.rb +32 -24
- data/lib/apicraft/middlewares/request_validator.rb +52 -0
- data/lib/apicraft/middlewares.rb +1 -0
- data/lib/apicraft/openapi/contract.rb +4 -4
- data/lib/apicraft/openapi/operation.rb +12 -4
- data/lib/apicraft/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7692b6e9a2cd444c2f5db48a932c78d64e4a23172575cafb76ed307c527c1ed3
|
4
|
+
data.tar.gz: 120c7cf23160c70761a168a815704bbcafc2e1c87901d5b2c58c037c840c4151
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dfe9dc9efc333d44b43825b5f0b5a3377ffdb1e3016a725c131b923ac15be131b5e8bc5e1ad6dc06cfd58ccc7ae493cf18b0c54846507491828550c884657e0b
|
7
|
+
data.tar.gz: a9bb65b6c85b07e5a17c52b99bcf59435cff0810191358b214fdd45bbea8cb5e181f5d7e1332431b74c9473f6a6a531e063e9391500eef78fad67b2b2d197231
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# APICraft Rails
|
1
|
+
# APICraft Rails
|
2
2
|
[![Build](https://github.com/apicraft-dev/apicraft-rails/actions/workflows/build.yml/badge.svg)](https://github.com/apicraft-dev/apicraft-rails/actions/workflows/build.yml)
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/apicraft-rails.svg)](https://badge.fury.io/rb/apicraft-rails)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/apicraft-rails.svg?v=1.0.0)](https://badge.fury.io/rb/apicraft-rails)
|
4
4
|
|
5
5
|
🚀 Accelerates your development by 2-3x with an API Design First approach. Seamlessly integrates with your Rails application server — no fancy tooling or expenses required.
|
6
6
|
|
@@ -12,23 +12,26 @@ It avoids the pitfalls of the code-first methodology, where contracts are auto-g
|
|
12
12
|
|
13
13
|
![APICraft Rails Logo](assets/apicraft_rails.png)
|
14
14
|
|
15
|
-
- [APICraft Rails
|
15
|
+
- [APICraft Rails](#apicraft-rails)
|
16
16
|
- [✨ Features](#-features)
|
17
17
|
- [🔜 Upcoming Features](#-upcoming-features)
|
18
18
|
- [🪄 Works Like Magic](#-works-like-magic)
|
19
19
|
- [🕊 API Design First Philosophy](#-api-design-first-philosophy)
|
20
20
|
- [🏗 Installation](#-installation)
|
21
21
|
- [⚙️ Usage](#️-usage)
|
22
|
-
- [
|
23
|
-
- [
|
24
|
-
- [
|
25
|
-
- [
|
22
|
+
- [🛡️ Request Validations](#️-request-validations)
|
23
|
+
- [🎭 Mocking](#-mocking)
|
24
|
+
- [🎮 Behaviour Mocking](#-behaviour-mocking)
|
25
|
+
- [🧐 Introspection](#-introspection)
|
26
|
+
- [📖 Documentation (Swagger docs and RapiDoc)](#-documentation-swagger-docs-and-rapidoc)
|
26
27
|
- [🔧 Configuration](#-configuration)
|
27
28
|
- [🤝 Contributing](#-contributing)
|
28
29
|
- [📝 License](#-license)
|
29
30
|
- [📘 Code of Conduct](#-code-of-conduct)
|
30
31
|
|
31
32
|
## ✨ Features
|
33
|
+
- 🛡️ **Automatic Request Validations** - Validates the request based on the openapi specs so that you don't need to add params validations everywhere in your controllers.
|
34
|
+
|
32
35
|
- 🧑💻️ **Dynamic Mock Data Generation** - Detects the specifications and instantly mounts working routes with mock responses. No extra configuration required.
|
33
36
|
|
34
37
|
- ⚙️ **Customizable Mock Responses** - Tailor mock responses to simulate different scenarios and edge cases, helping your team prepare for real-world conditions right from the start.
|
@@ -40,7 +43,6 @@ It avoids the pitfalls of the code-first methodology, where contracts are auto-g
|
|
40
43
|
- 🗂 **Easy Contracts Management** - Management of `openapi` specifications from within `app/contracts` directory. No new syntax, just plain old `openapi` standard with `.json` or `.yaml` formats
|
41
44
|
|
42
45
|
## 🔜 Upcoming Features
|
43
|
-
- 💢 **Request Validations** - Automatic request validations.
|
44
46
|
- 💎 **Clean & Custom Ruby DSL** - Support for a Ruby DSL alongwith the current `.json` and `.yaml` formats.
|
45
47
|
|
46
48
|
|
@@ -72,7 +74,7 @@ By adopting an API Design First approach with APICraft Rails, you can accelerate
|
|
72
74
|
Add this line to your application's Gemfile:
|
73
75
|
|
74
76
|
```ruby
|
75
|
-
gem 'apicraft-rails', '~> 0.
|
77
|
+
gem 'apicraft-rails', '~> 1.0.0'
|
76
78
|
```
|
77
79
|
|
78
80
|
And then execute:
|
@@ -89,8 +91,11 @@ module App
|
|
89
91
|
class Application < Rails::Application
|
90
92
|
# Rest of the configuration...
|
91
93
|
|
92
|
-
|
93
|
-
|
94
|
+
[
|
95
|
+
Apicraft::Middlewares::Mocker,
|
96
|
+
Apicraft::Middlewares::Introspector,
|
97
|
+
Apicraft::Middlewares::RequestValidator
|
98
|
+
].each { |mw| config.middleware.use mw }
|
94
99
|
|
95
100
|
Apicraft.configure do |config|
|
96
101
|
config.contracts_path = Rails.root.join("app/contracts")
|
@@ -117,7 +122,11 @@ my_rails_app/
|
|
117
122
|
│ │ ├── user.rb
|
118
123
|
│ │ └── order.rb
|
119
124
|
```
|
120
|
-
|
125
|
+
|
126
|
+
### 🛡️ Request Validations
|
127
|
+
All incoming requests will be validated against the defined schema. This ensures that by the time the params reach the controller they are adhering to all the schema requirements. It's enabled by default. You can customize the response of a failed validation. Check the [configuration section](#-configuration) section for a full list of options for this.
|
128
|
+
|
129
|
+
### 🎭 Mocking
|
121
130
|
**APICraft** dynamically generates mock APIs by interpreting contract specifications on the fly. You can request the mock response by passing `Apicraft-Mock: true` in the headers.
|
122
131
|
|
123
132
|
`https://yoursite.com/api/orders`
|
@@ -141,14 +150,16 @@ headers: {
|
|
141
150
|
]
|
142
151
|
```
|
143
152
|
|
144
|
-
### 🎮
|
153
|
+
### 🎮 Behaviour Mocking
|
145
154
|
The above is an example of a 200 response. If you have more responses documented you can force that behaviour using `Apicraft-Response-Code` header in the mock request.
|
155
|
+
You can find a list of all the supported headers in the [configuration section](#-configuration) that would allow you to manipulate the API Behaviour.
|
146
156
|
|
147
157
|
`https://yoursite.com/api/orders`
|
148
158
|
```
|
149
159
|
headers: {
|
150
160
|
Apicraft-Response-Code: 400
|
151
161
|
Apicraft-Mock: true
|
162
|
+
Apicraft-Delay: 5
|
152
163
|
}
|
153
164
|
```
|
154
165
|
```json
|
@@ -158,12 +169,12 @@ headers: {
|
|
158
169
|
}
|
159
170
|
```
|
160
171
|
|
161
|
-
### 🧐
|
162
|
-
All APIs are can be introspected. You can do so by passing the `Apicraft-
|
172
|
+
### 🧐 Introspection
|
173
|
+
All APIs are can be introspected. You can do so by passing the `Apicraft-Introspect` header.
|
163
174
|
|
164
175
|
```
|
165
176
|
headers: {
|
166
|
-
Apicraft-
|
177
|
+
Apicraft-Introspect: true
|
167
178
|
}
|
168
179
|
```
|
169
180
|
|
@@ -193,7 +204,7 @@ Example: `https://yoursite.com/api/orders`
|
|
193
204
|
}
|
194
205
|
}
|
195
206
|
```
|
196
|
-
### 📖
|
207
|
+
### 📖 Documentation (Swagger docs and RapiDoc)
|
197
208
|
|
198
209
|
Mount the documentation views in your route file.
|
199
210
|
|
@@ -223,6 +234,9 @@ module App
|
|
223
234
|
end
|
224
235
|
end
|
225
236
|
```
|
237
|
+
RapiDoc | SwaggerDoc
|
238
|
+
:-------------------------:|:-------------------------:
|
239
|
+
![](assets/rapidoc.png) | ![](assets/swaggerdoc.png)
|
226
240
|
|
227
241
|
## 🔧 Configuration
|
228
242
|
|
@@ -249,6 +263,10 @@ Apicraft.configure do |config|
|
|
249
263
|
# Defaults to true
|
250
264
|
config.strict_reference_validation = true
|
251
265
|
|
266
|
+
# When simulating delay using the mocks, the max
|
267
|
+
# delay in seconds that can be simulated
|
268
|
+
config.max_allowed_delay = 30
|
269
|
+
|
252
270
|
config.headers = {
|
253
271
|
# The name of the header used to control
|
254
272
|
# the response code of the mock
|
@@ -257,11 +275,28 @@ Apicraft.configure do |config|
|
|
257
275
|
|
258
276
|
# The name of the header to introspect the API.
|
259
277
|
# Defaults to Apicraft-Introspect
|
260
|
-
introspect: "Apicraft-Introspect"
|
278
|
+
introspect: "Apicraft-Introspect",
|
261
279
|
|
262
280
|
# The name of the header to mock the API.
|
263
281
|
# Defaults to Apicraft-Mock
|
264
|
-
mock: "Apicraft-Mock"
|
282
|
+
mock: "Apicraft-Mock",
|
283
|
+
|
284
|
+
# Delay simulation header name
|
285
|
+
delay: "Apicraft-Delay"
|
286
|
+
}
|
287
|
+
|
288
|
+
config.request_validation = {
|
289
|
+
enabled: true,
|
290
|
+
|
291
|
+
# Return the http code for validation errors, defaults to 400
|
292
|
+
http_code: 400,
|
293
|
+
|
294
|
+
# Return a custom response body, defaults to `{ message: "..." }`
|
295
|
+
response_body: proc do |ex|
|
296
|
+
{
|
297
|
+
message: ex.message
|
298
|
+
}
|
299
|
+
end
|
265
300
|
}
|
266
301
|
end
|
267
302
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apicraft
|
4
|
+
module Concerns
|
5
|
+
# Helper class with shared methods
|
6
|
+
module MiddlewareUtil
|
7
|
+
def config
|
8
|
+
@config ||= Apicraft.config
|
9
|
+
end
|
10
|
+
|
11
|
+
def convertor(format)
|
12
|
+
return if format.blank?
|
13
|
+
|
14
|
+
Apicraft::Constants::MIME_TYPE_CONVERTORS[format]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/apicraft/concerns.rb
CHANGED
data/lib/apicraft/config.rb
CHANGED
@@ -13,18 +13,22 @@ module Apicraft
|
|
13
13
|
response_code: "Apicraft-Response-Code",
|
14
14
|
introspect: "Apicraft-Introspect",
|
15
15
|
mock: "Apicraft-Mock",
|
16
|
+
delay: "Apicraft-Delay",
|
16
17
|
content_type: "Content-Type"
|
17
18
|
},
|
18
19
|
mocks: true,
|
19
20
|
introspection: true,
|
20
21
|
strict_reference_validation: true,
|
21
|
-
|
22
|
+
max_allowed_delay: 30,
|
23
|
+
request_validation: {
|
24
|
+
enabled: true,
|
25
|
+
http_code: 400,
|
26
|
+
response_body: proc { |ex| { message: ex.message } }
|
27
|
+
}
|
22
28
|
}.with_indifferent_access
|
23
29
|
|
24
|
-
def initialize
|
25
|
-
@opts = DEFAULTS
|
26
|
-
opts
|
27
|
-
).with_indifferent_access
|
30
|
+
def initialize
|
31
|
+
@opts = DEFAULTS
|
28
32
|
end
|
29
33
|
|
30
34
|
def headers
|
@@ -47,6 +51,26 @@ module Apicraft
|
|
47
51
|
@opts[:introspection]
|
48
52
|
end
|
49
53
|
|
54
|
+
def max_allowed_delay
|
55
|
+
@opts[:max_allowed_delay]
|
56
|
+
end
|
57
|
+
|
58
|
+
def request_validation
|
59
|
+
@opts[:request_validation]
|
60
|
+
end
|
61
|
+
|
62
|
+
def request_validation_enabled?
|
63
|
+
@opts[:request_validation][:enabled]
|
64
|
+
end
|
65
|
+
|
66
|
+
def request_validation_http_code
|
67
|
+
@opts[:request_validation][:http_code] || DEFAULTS[:request_validation][:http_code]
|
68
|
+
end
|
69
|
+
|
70
|
+
def request_validation_response_body
|
71
|
+
@opts[:request_validation][:response_body]
|
72
|
+
end
|
73
|
+
|
50
74
|
def contracts_path=(contracts_path)
|
51
75
|
@opts[:contracts_path] = contracts_path
|
52
76
|
end
|
@@ -63,8 +87,14 @@ module Apicraft
|
|
63
87
|
@opts[:strict_reference_validation] = enabled
|
64
88
|
end
|
65
89
|
|
66
|
-
def
|
67
|
-
@opts[:
|
90
|
+
def request_validation=(request_validation_opts)
|
91
|
+
@opts[:request_validation] = @opts[:request_validation].merge(
|
92
|
+
request_validation_opts.with_indifferent_access
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def max_allowed_delay=(enabled)
|
97
|
+
@opts[:max_allowed_delay] = enabled
|
68
98
|
end
|
69
99
|
|
70
100
|
def headers=(headers)
|
data/lib/apicraft/errors.rb
CHANGED
@@ -4,6 +4,8 @@ module Apicraft
|
|
4
4
|
module Middlewares
|
5
5
|
# Apicraft Middleware to handle API Introspection.
|
6
6
|
class Introspector
|
7
|
+
include Concerns::MiddlewareUtil
|
8
|
+
|
7
9
|
def initialize(app)
|
8
10
|
@app = app
|
9
11
|
end
|
@@ -30,10 +32,6 @@ module Apicraft
|
|
30
32
|
|
31
33
|
private
|
32
34
|
|
33
|
-
def config
|
34
|
-
@config ||= Apicraft.config
|
35
|
-
end
|
36
|
-
|
37
35
|
def introspect?(request)
|
38
36
|
request.headers[config.headers[:introspect]].present?
|
39
37
|
end
|
@@ -5,6 +5,8 @@ module Apicraft
|
|
5
5
|
# Apicraft Middleware to handle routing
|
6
6
|
# and make mock calls available.
|
7
7
|
class Mocker
|
8
|
+
include Concerns::MiddlewareUtil
|
9
|
+
|
8
10
|
def initialize(app)
|
9
11
|
@app = app
|
10
12
|
end
|
@@ -15,28 +17,15 @@ module Apicraft
|
|
15
17
|
request = ActionDispatch::Request.new(env)
|
16
18
|
return @app.call(env) unless mock?(request)
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
)
|
21
|
-
raise Errors::InvalidContract if contract.blank?
|
22
|
-
|
23
|
-
operation = contract.operation(
|
24
|
-
request.method, request.path_info
|
25
|
-
)
|
26
|
-
raise Errors::InvalidOperation if operation.blank?
|
20
|
+
use_delay!(request)
|
21
|
+
contract = find_contract!(request)
|
22
|
+
operation = find_operation!(contract, request)
|
27
23
|
|
28
24
|
code = request.headers[config.headers[:response_code]] || "200"
|
29
25
|
response = operation.response_for(code.to_s)
|
30
26
|
raise Errors::InvalidResponse if response.blank?
|
31
27
|
|
32
|
-
|
33
|
-
# If passed we use it and the response format.
|
34
|
-
# If not we use the first format from the specs.
|
35
|
-
request.format.to_s
|
36
|
-
# indicates that not format was specified.
|
37
|
-
format = nil
|
38
|
-
|
39
|
-
content, content_type = response.mock(format)
|
28
|
+
content, content_type = response.mock(request.content_type)
|
40
29
|
|
41
30
|
[
|
42
31
|
code.to_i,
|
@@ -51,18 +40,37 @@ module Apicraft
|
|
51
40
|
|
52
41
|
private
|
53
42
|
|
54
|
-
def
|
55
|
-
|
43
|
+
def mock?(request)
|
44
|
+
request.headers[config.headers[:mock]].present?
|
56
45
|
end
|
57
46
|
|
58
|
-
def
|
59
|
-
|
47
|
+
def find_contract!(request)
|
48
|
+
contract = Apicraft::Openapi::Contract.find_by_operation(
|
49
|
+
request.method, request.path_info
|
50
|
+
)
|
51
|
+
raise Errors::InvalidContract if contract.blank?
|
60
52
|
|
61
|
-
|
53
|
+
contract
|
62
54
|
end
|
63
55
|
|
64
|
-
def
|
65
|
-
|
56
|
+
def find_operation!(contract, request)
|
57
|
+
operation = contract.operation(
|
58
|
+
request.method, request.path_info
|
59
|
+
)
|
60
|
+
raise Errors::InvalidOperation if operation.blank?
|
61
|
+
|
62
|
+
operation
|
63
|
+
end
|
64
|
+
|
65
|
+
def use_delay!(request)
|
66
|
+
request_delay = delay(request)
|
67
|
+
raise Errors::DelayTooHigh if request_delay > config.max_allowed_delay
|
68
|
+
|
69
|
+
sleep(request_delay)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delay(request)
|
73
|
+
request.headers[config.headers[:delay]].to_i
|
66
74
|
end
|
67
75
|
end
|
68
76
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Apicraft
|
4
|
+
module Middlewares
|
5
|
+
# Middleware to handle Request Validation.
|
6
|
+
class RequestValidator
|
7
|
+
include Concerns::MiddlewareUtil
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
return @app.call(env) unless validate?
|
15
|
+
|
16
|
+
request = ActionDispatch::Request.new(env)
|
17
|
+
content_type = request.content_type
|
18
|
+
|
19
|
+
operation = Apicraft::Openapi::Contract.find_by_operation(
|
20
|
+
request.method, request.path_info
|
21
|
+
)&.operation(
|
22
|
+
request.method, request.path_info
|
23
|
+
)
|
24
|
+
return @app.call(env) if operation.blank?
|
25
|
+
|
26
|
+
operation.validate_request_body(
|
27
|
+
content_type,
|
28
|
+
request.params
|
29
|
+
)
|
30
|
+
@app.call(env)
|
31
|
+
rescue OpenAPIParser::OpenAPIError => e
|
32
|
+
[
|
33
|
+
config.request_validation_http_code,
|
34
|
+
{ 'Content-Type': content_type },
|
35
|
+
[
|
36
|
+
response_body(e)&.send(convertor(content_type))
|
37
|
+
].compact
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def validate?
|
44
|
+
config.request_validation_enabled?
|
45
|
+
end
|
46
|
+
|
47
|
+
def response_body(ex)
|
48
|
+
config.request_validation_response_body.call(ex)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/apicraft/middlewares.rb
CHANGED
@@ -15,10 +15,10 @@ module Apicraft
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def operation(method, path)
|
18
|
-
with_cache("operation-#{method.downcase}-#{path}") do
|
19
|
-
|
20
|
-
|
21
|
-
end
|
18
|
+
# with_cache("operation-#{method.downcase}-#{path}") do
|
19
|
+
op = document.request_operation(method.downcase, path)
|
20
|
+
Operation.new(op) if op.present?
|
21
|
+
# end
|
22
22
|
end
|
23
23
|
|
24
24
|
class << self
|
@@ -8,15 +8,16 @@ module Apicraft
|
|
8
8
|
attr_accessor :operation
|
9
9
|
|
10
10
|
def initialize(operation)
|
11
|
-
@operation = operation
|
11
|
+
@operation = operation
|
12
|
+
@operation_object = operation.operation_object
|
12
13
|
end
|
13
14
|
|
14
15
|
def responses
|
15
|
-
@
|
16
|
+
@operation_object.responses
|
16
17
|
end
|
17
18
|
|
18
19
|
def summary
|
19
|
-
@
|
20
|
+
@operation_object.summary
|
20
21
|
end
|
21
22
|
|
22
23
|
def response_for(code)
|
@@ -29,7 +30,14 @@ module Apicraft
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def raw_schema
|
32
|
-
|
33
|
+
@operation_object.raw_schema
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_request_body(content_type, body)
|
37
|
+
operation.validate_request_body(
|
38
|
+
content_type,
|
39
|
+
body
|
40
|
+
)
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
data/lib/apicraft/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apicraft-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abhishek Sarkar
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -126,6 +126,7 @@ files:
|
|
126
126
|
- lib/apicraft-rails.rb
|
127
127
|
- lib/apicraft/concerns.rb
|
128
128
|
- lib/apicraft/concerns/cacheable.rb
|
129
|
+
- lib/apicraft/concerns/middleware_util.rb
|
129
130
|
- lib/apicraft/config.rb
|
130
131
|
- lib/apicraft/constants.rb
|
131
132
|
- lib/apicraft/errors.rb
|
@@ -133,6 +134,7 @@ files:
|
|
133
134
|
- lib/apicraft/middlewares.rb
|
134
135
|
- lib/apicraft/middlewares/introspector.rb
|
135
136
|
- lib/apicraft/middlewares/mocker.rb
|
137
|
+
- lib/apicraft/middlewares/request_validator.rb
|
136
138
|
- lib/apicraft/mocker.rb
|
137
139
|
- lib/apicraft/mocker/all_of.rb
|
138
140
|
- lib/apicraft/mocker/any_of.rb
|
@@ -183,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
185
|
- !ruby/object:Gem::Version
|
184
186
|
version: '0'
|
185
187
|
requirements: []
|
186
|
-
rubygems_version: 3.
|
188
|
+
rubygems_version: 3.2.33
|
187
189
|
signing_key:
|
188
190
|
specification_version: 4
|
189
191
|
summary: APICraft Rails - Simplified API Design First Development
|