rapitapir 0.1.1 โ 2.0.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/.rubocop.yml +7 -7
- data/.rubocop_todo.yml +83 -0
- data/README.md +1319 -235
- data/RUBY_WEEKLY_LAUNCH_POST.md +219 -0
- data/docs/RAILS_INTEGRATION_IMPLEMENTATION.md +209 -0
- data/docs/SINATRA_EXTENSION.md +399 -348
- data/docs/STRICT_VALIDATION.md +229 -0
- data/docs/VALIDATION_IMPROVEMENTS.md +218 -0
- data/docs/ai-integration-plan.md +112 -0
- data/docs/auto-derivation.md +505 -92
- data/docs/endpoint-definition.md +536 -129
- data/docs/n8n-integration.md +212 -0
- data/docs/observability.md +810 -500
- data/docs/using-mcp.md +93 -0
- data/examples/ai/knowledge_base_rag.rb +83 -0
- data/examples/ai/user_management_mcp.rb +92 -0
- data/examples/ai/user_validation_llm.rb +187 -0
- data/examples/rails/RAILS_8_GUIDE.md +165 -0
- data/examples/rails/RAILS_LOADING_FIX.rb +35 -0
- data/examples/rails/README.md +497 -0
- data/examples/rails/comprehensive_test.rb +91 -0
- data/examples/rails/config/routes.rb +48 -0
- data/examples/rails/debug_controller.rb +63 -0
- data/examples/rails/detailed_test.rb +46 -0
- data/examples/rails/enhanced_users_controller.rb +278 -0
- data/examples/rails/final_server_test.rb +50 -0
- data/examples/rails/hello_world_app.rb +116 -0
- data/examples/rails/hello_world_controller.rb +186 -0
- data/examples/rails/hello_world_routes.rb +28 -0
- data/examples/rails/rails8_minimal_demo.rb +132 -0
- data/examples/rails/rails8_simple_demo.rb +140 -0
- data/examples/rails/rails8_working_demo.rb +255 -0
- data/examples/rails/real_world_blog_api.rb +510 -0
- data/examples/rails/server_test.rb +46 -0
- data/examples/rails/test_direct_processing.rb +41 -0
- data/examples/rails/test_hello_world.rb +80 -0
- data/examples/rails/test_rails_integration.rb +54 -0
- data/examples/rails/traditional_app/Gemfile +37 -0
- data/examples/rails/traditional_app/README.md +265 -0
- data/examples/rails/traditional_app/app/controllers/api/v1/posts_controller.rb +254 -0
- data/examples/rails/traditional_app/app/controllers/api/v1/users_controller.rb +220 -0
- data/examples/rails/traditional_app/app/controllers/application_controller.rb +86 -0
- data/examples/rails/traditional_app/app/controllers/application_controller_simplified.rb +87 -0
- data/examples/rails/traditional_app/app/controllers/documentation_controller.rb +149 -0
- data/examples/rails/traditional_app/app/controllers/health_controller.rb +42 -0
- data/examples/rails/traditional_app/config/routes.rb +25 -0
- data/examples/rails/traditional_app/config/routes_best_practice.rb +25 -0
- data/examples/rails/traditional_app/config/routes_simplified.rb +36 -0
- data/examples/rails/traditional_app_runnable.rb +406 -0
- data/examples/rails/users_controller.rb +4 -1
- data/examples/serverless/Gemfile +43 -0
- data/examples/serverless/QUICKSTART.md +331 -0
- data/examples/serverless/README.md +520 -0
- data/examples/serverless/aws_lambda_example.rb +307 -0
- data/examples/serverless/aws_sam_template.yaml +215 -0
- data/examples/serverless/azure_functions_example.rb +407 -0
- data/examples/serverless/deploy.rb +204 -0
- data/examples/serverless/gcp_cloud_functions_example.rb +367 -0
- data/examples/serverless/gcp_function.yaml +23 -0
- data/examples/serverless/host.json +24 -0
- data/examples/serverless/package.json +32 -0
- data/examples/serverless/spec/aws_lambda_spec.rb +196 -0
- data/examples/serverless/spec/spec_helper.rb +89 -0
- data/examples/serverless/vercel.json +31 -0
- data/examples/serverless/vercel_example.rb +404 -0
- data/examples/strict_validation_examples.rb +104 -0
- data/examples/validation_error_examples.rb +173 -0
- data/lib/rapitapir/ai/llm_instruction.rb +456 -0
- data/lib/rapitapir/ai/mcp.rb +134 -0
- data/lib/rapitapir/ai/rag.rb +287 -0
- data/lib/rapitapir/ai/rag_middleware.rb +147 -0
- data/lib/rapitapir/auth/oauth2.rb +43 -57
- data/lib/rapitapir/cli/command.rb +362 -2
- data/lib/rapitapir/cli/mcp_export.rb +18 -0
- data/lib/rapitapir/cli/validator.rb +2 -6
- data/lib/rapitapir/core/endpoint.rb +59 -6
- data/lib/rapitapir/core/enhanced_endpoint.rb +2 -6
- data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +53 -0
- data/lib/rapitapir/endpoint_registry.rb +47 -0
- data/lib/rapitapir/observability/health_check.rb +4 -4
- data/lib/rapitapir/observability/logging.rb +10 -10
- data/lib/rapitapir/schema.rb +2 -2
- data/lib/rapitapir/server/rack_adapter.rb +1 -3
- data/lib/rapitapir/server/rails/configuration.rb +77 -0
- data/lib/rapitapir/server/rails/controller_base.rb +185 -0
- data/lib/rapitapir/server/rails/documentation_helpers.rb +76 -0
- data/lib/rapitapir/server/rails/resource_builder.rb +181 -0
- data/lib/rapitapir/server/rails/routes.rb +114 -0
- data/lib/rapitapir/server/rails_adapter.rb +10 -3
- data/lib/rapitapir/server/rails_adapter_class.rb +1 -3
- data/lib/rapitapir/server/rails_controller.rb +1 -3
- data/lib/rapitapir/server/rails_integration.rb +67 -0
- data/lib/rapitapir/server/rails_response_handler.rb +16 -3
- data/lib/rapitapir/server/sinatra_adapter.rb +29 -5
- data/lib/rapitapir/server/sinatra_integration.rb +4 -4
- data/lib/rapitapir/sinatra/extension.rb +2 -2
- data/lib/rapitapir/sinatra/oauth2_helpers.rb +34 -40
- data/lib/rapitapir/types/array.rb +4 -0
- data/lib/rapitapir/types/auto_derivation.rb +4 -18
- data/lib/rapitapir/types/datetime.rb +1 -3
- data/lib/rapitapir/types/float.rb +2 -6
- data/lib/rapitapir/types/hash.rb +40 -2
- data/lib/rapitapir/types/integer.rb +4 -12
- data/lib/rapitapir/types/object.rb +6 -2
- data/lib/rapitapir/types.rb +6 -2
- data/lib/rapitapir/version.rb +1 -1
- data/lib/rapitapir.rb +5 -3
- data/rapitapir.gemspec +7 -5
- metadata +116 -16
@@ -0,0 +1,406 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Minimal runnable Rails application demonstrating RapiTapir integration
|
4
|
+
# This shows the traditional Rails app structure in a single file for easy testing
|
5
|
+
|
6
|
+
require 'bundler/inline'
|
7
|
+
|
8
|
+
gemfile do
|
9
|
+
source 'https://rubygems.org'
|
10
|
+
gem 'rails', '~> 8.0'
|
11
|
+
gem 'sqlite3'
|
12
|
+
gem 'puma'
|
13
|
+
end
|
14
|
+
|
15
|
+
require 'rails/all'
|
16
|
+
require_relative '../../../lib/rapitapir'
|
17
|
+
|
18
|
+
# Simulate ActiveRecord models for the demo
|
19
|
+
class User < ActiveRecord::Base
|
20
|
+
validates :email, presence: true, uniqueness: true
|
21
|
+
validates :name, presence: true
|
22
|
+
end
|
23
|
+
|
24
|
+
class Post < ActiveRecord::Base
|
25
|
+
belongs_to :user
|
26
|
+
validates :title, presence: true
|
27
|
+
validates :content, presence: true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Rails Application Setup
|
31
|
+
class TraditionalApp < Rails::Application
|
32
|
+
config.load_defaults 8.0
|
33
|
+
config.api_only = true
|
34
|
+
config.eager_load = false
|
35
|
+
config.logger = Logger.new(STDOUT)
|
36
|
+
config.log_level = :info
|
37
|
+
config.secret_key_base = 'demo_secret_key_base_for_traditional_app_example'
|
38
|
+
|
39
|
+
# Rails 8 specific configurations
|
40
|
+
config.autoload_lib(ignore: %w[assets tasks])
|
41
|
+
end
|
42
|
+
|
43
|
+
Rails.application.initialize!
|
44
|
+
|
45
|
+
# Database setup
|
46
|
+
ActiveRecord::Base.establish_connection(
|
47
|
+
adapter: 'sqlite3',
|
48
|
+
database: ':memory:'
|
49
|
+
)
|
50
|
+
|
51
|
+
# Create tables
|
52
|
+
ActiveRecord::Schema.define do
|
53
|
+
create_table :users do |t|
|
54
|
+
t.string :name, null: false
|
55
|
+
t.string :email, null: false
|
56
|
+
t.text :bio
|
57
|
+
t.timestamps
|
58
|
+
end
|
59
|
+
|
60
|
+
create_table :posts do |t|
|
61
|
+
t.references :user, null: false, foreign_key: true
|
62
|
+
t.string :title, null: false
|
63
|
+
t.text :content, null: false
|
64
|
+
t.boolean :published, default: false
|
65
|
+
t.timestamps
|
66
|
+
end
|
67
|
+
|
68
|
+
add_index :users, :email, unique: true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Seed some data
|
72
|
+
user1 = User.create!(name: "Alice Johnson", email: "alice@example.com", bio: "Tech blogger")
|
73
|
+
user2 = User.create!(name: "Bob Smith", email: "bob@example.com", bio: "Developer")
|
74
|
+
|
75
|
+
Post.create!(
|
76
|
+
user: user1,
|
77
|
+
title: "Getting Started with RapiTapir",
|
78
|
+
content: "RapiTapir makes API development in Ruby a breeze...",
|
79
|
+
published: true
|
80
|
+
)
|
81
|
+
|
82
|
+
Post.create!(
|
83
|
+
user: user2,
|
84
|
+
title: "Rails + RapiTapir Best Practices",
|
85
|
+
content: "Here are some patterns I've learned...",
|
86
|
+
published: true
|
87
|
+
)
|
88
|
+
|
89
|
+
# ApplicationController - Base controller with health check
|
90
|
+
class ApplicationController < RapiTapir::Server::Rails::ControllerBase
|
91
|
+
# Global configuration for all controllers
|
92
|
+
rapitapir do
|
93
|
+
# Enable development features (automatic docs, etc.)
|
94
|
+
development_defaults!
|
95
|
+
|
96
|
+
# Global error handling
|
97
|
+
error_out(json_body(error: T.string, details: T.string.optional), 500)
|
98
|
+
error_out(json_body(error: T.string), 401)
|
99
|
+
error_out(json_body(error: T.string), 403)
|
100
|
+
error_out(json_body(error: T.string), 404)
|
101
|
+
error_out(json_body(error: T.string, errors: T.array(T.string).optional), 422)
|
102
|
+
|
103
|
+
# Health check endpoint - no separate controller needed!
|
104
|
+
GET('/health')
|
105
|
+
.out(json_body(
|
106
|
+
status: T.string,
|
107
|
+
timestamp: T.string,
|
108
|
+
version: T.string,
|
109
|
+
environment: T.string,
|
110
|
+
database: T.string,
|
111
|
+
services: T.hash(redis: T.string)
|
112
|
+
))
|
113
|
+
.summary("Health check")
|
114
|
+
.description("Check API and service health")
|
115
|
+
.tag("System")
|
116
|
+
end
|
117
|
+
|
118
|
+
def health_check
|
119
|
+
{
|
120
|
+
status: 'ok',
|
121
|
+
timestamp: Time.current.iso8601,
|
122
|
+
version: '1.0.0',
|
123
|
+
environment: Rails.env,
|
124
|
+
database: database_status,
|
125
|
+
services: {
|
126
|
+
redis: redis_status
|
127
|
+
}
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
# Helper method for standardized error responses
|
134
|
+
def render_error(message, status, details: nil, errors: nil)
|
135
|
+
payload = { error: message }
|
136
|
+
payload[:details] = details if details
|
137
|
+
payload[:errors] = errors if errors
|
138
|
+
|
139
|
+
render json: payload, status: status
|
140
|
+
end
|
141
|
+
|
142
|
+
# Helper for pagination metadata
|
143
|
+
def pagination_metadata(collection, page, per_page)
|
144
|
+
total = collection.respond_to?(:count) ? collection.count : collection.size
|
145
|
+
{
|
146
|
+
page: page,
|
147
|
+
per_page: per_page,
|
148
|
+
total: total,
|
149
|
+
total_pages: (total.to_f / per_page).ceil,
|
150
|
+
has_next: page < (total.to_f / per_page).ceil,
|
151
|
+
has_prev: page > 1
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
def database_status
|
158
|
+
ActiveRecord::Base.connection.execute('SELECT 1')
|
159
|
+
'connected'
|
160
|
+
rescue => e
|
161
|
+
Rails.logger.error "Database check failed: #{e.message}"
|
162
|
+
'disconnected'
|
163
|
+
end
|
164
|
+
|
165
|
+
def redis_status
|
166
|
+
'not_configured'
|
167
|
+
rescue => e
|
168
|
+
Rails.logger.error "Redis check failed: #{e.message}"
|
169
|
+
'disconnected'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Api::V1::UsersController - Example API controller
|
174
|
+
class Api::V1::UsersController < ApplicationController
|
175
|
+
rapitapir do
|
176
|
+
# User type definitions
|
177
|
+
user_type = T.hash(
|
178
|
+
id: T.integer,
|
179
|
+
email: T.string,
|
180
|
+
name: T.string,
|
181
|
+
bio: T.string.optional,
|
182
|
+
created_at: T.string,
|
183
|
+
updated_at: T.string
|
184
|
+
)
|
185
|
+
|
186
|
+
# List users with pagination
|
187
|
+
GET('/api/v1/users')
|
188
|
+
.in(query(:page, T.integer.default(1)))
|
189
|
+
.in(query(:per_page, T.integer.default(10)))
|
190
|
+
.out(json_body(
|
191
|
+
users: T.array(user_type),
|
192
|
+
pagination: T.hash(
|
193
|
+
page: T.integer,
|
194
|
+
per_page: T.integer,
|
195
|
+
total: T.integer,
|
196
|
+
total_pages: T.integer
|
197
|
+
)
|
198
|
+
))
|
199
|
+
.summary("List users")
|
200
|
+
.description("Get a paginated list of all users")
|
201
|
+
.tag("Users")
|
202
|
+
|
203
|
+
# Get specific user
|
204
|
+
GET('/api/v1/users/:id')
|
205
|
+
.in(path(:id, T.integer))
|
206
|
+
.out(json_body(user: user_type))
|
207
|
+
.error_out(json_body(error: T.string), 404)
|
208
|
+
.summary("Get user by ID")
|
209
|
+
.tag("Users")
|
210
|
+
|
211
|
+
# Create new user
|
212
|
+
POST('/api/v1/users')
|
213
|
+
.in(json_body(
|
214
|
+
name: T.string,
|
215
|
+
email: T.string,
|
216
|
+
bio: T.string.optional
|
217
|
+
))
|
218
|
+
.out(json_body(user: user_type), 201)
|
219
|
+
.error_out(json_body(errors: T.array(T.string)), 422)
|
220
|
+
.summary("Create a new user")
|
221
|
+
.tag("Users")
|
222
|
+
end
|
223
|
+
|
224
|
+
def list_users
|
225
|
+
page = inputs[:page]
|
226
|
+
per_page = [inputs[:per_page], 50].min # Cap at 50
|
227
|
+
|
228
|
+
users_scope = User.all
|
229
|
+
total = users_scope.count
|
230
|
+
users = users_scope.offset((page - 1) * per_page).limit(per_page)
|
231
|
+
|
232
|
+
{
|
233
|
+
users: users.map(&method(:serialize_user)),
|
234
|
+
pagination: pagination_metadata(users_scope, page, per_page)
|
235
|
+
}
|
236
|
+
end
|
237
|
+
|
238
|
+
def get_user
|
239
|
+
user = User.find_by(id: inputs[:id])
|
240
|
+
return render_error("User not found", 404) unless user
|
241
|
+
|
242
|
+
{ user: serialize_user(user) }
|
243
|
+
end
|
244
|
+
|
245
|
+
def create_user
|
246
|
+
user = User.new(user_params)
|
247
|
+
|
248
|
+
if user.save
|
249
|
+
render json: { user: serialize_user(user) }, status: 201
|
250
|
+
else
|
251
|
+
render_error("Validation failed", 422, errors: user.errors.full_messages)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def user_params
|
258
|
+
inputs.slice(:name, :email, :bio).compact
|
259
|
+
end
|
260
|
+
|
261
|
+
def serialize_user(user)
|
262
|
+
{
|
263
|
+
id: user.id,
|
264
|
+
name: user.name,
|
265
|
+
email: user.email,
|
266
|
+
bio: user.bio,
|
267
|
+
created_at: user.created_at.iso8601,
|
268
|
+
updated_at: user.updated_at.iso8601
|
269
|
+
}
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Api::V1::PostsController - Posts API
|
274
|
+
class Api::V1::PostsController < ApplicationController
|
275
|
+
rapitapir do
|
276
|
+
# Post schema
|
277
|
+
post_type = T.hash(
|
278
|
+
id: T.integer,
|
279
|
+
title: T.string,
|
280
|
+
content: T.string,
|
281
|
+
published: T.boolean,
|
282
|
+
user: T.hash(
|
283
|
+
id: T.integer,
|
284
|
+
name: T.string,
|
285
|
+
email: T.string
|
286
|
+
),
|
287
|
+
created_at: T.string,
|
288
|
+
updated_at: T.string
|
289
|
+
)
|
290
|
+
|
291
|
+
# List posts
|
292
|
+
GET('/api/v1/posts')
|
293
|
+
.in(query(:published, T.boolean.optional))
|
294
|
+
.in(query(:page, T.integer.default(1)))
|
295
|
+
.out(json_body(
|
296
|
+
posts: T.array(post_type),
|
297
|
+
pagination: T.hash(
|
298
|
+
page: T.integer,
|
299
|
+
total: T.integer,
|
300
|
+
total_pages: T.integer
|
301
|
+
)
|
302
|
+
))
|
303
|
+
.summary("List posts")
|
304
|
+
.tag("Posts")
|
305
|
+
|
306
|
+
# Get specific post
|
307
|
+
GET('/api/v1/posts/:id')
|
308
|
+
.in(path(:id, T.integer))
|
309
|
+
.out(json_body(post: post_type))
|
310
|
+
.error_out(json_body(error: T.string), 404)
|
311
|
+
.summary("Get post by ID")
|
312
|
+
.tag("Posts")
|
313
|
+
end
|
314
|
+
|
315
|
+
def list_posts
|
316
|
+
posts_scope = Post.includes(:user)
|
317
|
+
|
318
|
+
# Apply filters
|
319
|
+
posts_scope = posts_scope.where(published: inputs[:published]) if inputs.key?(:published)
|
320
|
+
|
321
|
+
# Pagination
|
322
|
+
page = inputs[:page]
|
323
|
+
per_page = 10
|
324
|
+
total = posts_scope.count
|
325
|
+
posts = posts_scope.offset((page - 1) * per_page).limit(per_page)
|
326
|
+
|
327
|
+
{
|
328
|
+
posts: posts.map(&method(:serialize_post)),
|
329
|
+
pagination: pagination_metadata(posts_scope, page, per_page)
|
330
|
+
}
|
331
|
+
end
|
332
|
+
|
333
|
+
def get_post
|
334
|
+
post = Post.includes(:user).find_by(id: inputs[:id])
|
335
|
+
return render_error("Post not found", 404) unless post
|
336
|
+
|
337
|
+
{ post: serialize_post(post) }
|
338
|
+
end
|
339
|
+
|
340
|
+
private
|
341
|
+
|
342
|
+
def serialize_post(post)
|
343
|
+
{
|
344
|
+
id: post.id,
|
345
|
+
title: post.title,
|
346
|
+
content: post.content,
|
347
|
+
published: post.published,
|
348
|
+
user: {
|
349
|
+
id: post.user.id,
|
350
|
+
name: post.user.name,
|
351
|
+
email: post.user.email
|
352
|
+
},
|
353
|
+
created_at: post.created_at.iso8601,
|
354
|
+
updated_at: post.updated_at.iso8601
|
355
|
+
}
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Application routing
|
360
|
+
Rails.application.routes.draw do
|
361
|
+
# Health check (from ApplicationController)
|
362
|
+
rapitapir_routes_for ApplicationController
|
363
|
+
|
364
|
+
# API v1 routes - RapiTapir auto-generates routes from endpoint definitions
|
365
|
+
namespace :api do
|
366
|
+
namespace :v1 do
|
367
|
+
rapitapir_routes_for Api::V1::UsersController
|
368
|
+
rapitapir_routes_for Api::V1::PostsController
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# Documentation routes (automatically added by development_defaults!)
|
373
|
+
# Available at:
|
374
|
+
# - GET /docs -> Swagger UI
|
375
|
+
# - GET /openapi.json -> OpenAPI 3.0 specification
|
376
|
+
|
377
|
+
# Catch-all for unmatched routes
|
378
|
+
match '*path', to: proc { |env|
|
379
|
+
[404, { 'Content-Type' => 'application/json' }, [{ error: 'Route not found' }.to_json]]
|
380
|
+
}, via: :all
|
381
|
+
end
|
382
|
+
|
383
|
+
# Start the server
|
384
|
+
if __FILE__ == $0
|
385
|
+
puts "๐ Starting Traditional Rails App with RapiTapir on http://localhost:3000"
|
386
|
+
puts "๐ API Documentation: http://localhost:3000/docs"
|
387
|
+
puts "๐ OpenAPI Spec: http://localhost:3000/openapi.json"
|
388
|
+
puts "๐ฅ Health Check: http://localhost:3000/health"
|
389
|
+
puts ""
|
390
|
+
puts "๐ Available Endpoints:"
|
391
|
+
puts " GET /health - System health check"
|
392
|
+
puts " GET /api/v1/users - List users"
|
393
|
+
puts " GET /api/v1/users/1 - Get specific user"
|
394
|
+
puts " POST /api/v1/users - Create new user"
|
395
|
+
puts " GET /api/v1/posts - List posts"
|
396
|
+
puts " GET /api/v1/posts/1 - Get specific post"
|
397
|
+
puts ""
|
398
|
+
puts "๐งช Test Examples:"
|
399
|
+
puts " curl http://localhost:3000/health"
|
400
|
+
puts " curl http://localhost:3000/api/v1/users"
|
401
|
+
puts " curl http://localhost:3000/api/v1/posts?published=true"
|
402
|
+
puts ""
|
403
|
+
|
404
|
+
require 'rack'
|
405
|
+
Rack::Handler::WEBrick.run(Rails.application, Port: 3000)
|
406
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Example Rails controller using RapiTapir
|
3
|
+
# LEGACY Example Rails controller using RapiTapir (verbose approach)
|
4
|
+
#
|
5
|
+
# โ ๏ธ This example shows the OLD way of integrating RapiTapir with Rails.
|
6
|
+
# ๐ For the NEW, enhanced approach, see enhanced_users_controller.rb
|
4
7
|
#
|
5
8
|
# To use this in a Rails app:
|
6
9
|
# 1. Add this file to app/controllers/
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Gemfile for serverless deployments
|
2
|
+
source 'https://rubygems.org'
|
3
|
+
|
4
|
+
# Core RapiTapir dependency
|
5
|
+
gem 'rapitapir', path: '../..' # Use local version for examples
|
6
|
+
|
7
|
+
# Serverless runtime dependencies
|
8
|
+
gem 'sinatra', '~> 3.0'
|
9
|
+
gem 'rack', '~> 2.2'
|
10
|
+
gem 'json', '~> 2.6'
|
11
|
+
|
12
|
+
# Platform-specific gems
|
13
|
+
group :aws do
|
14
|
+
gem 'aws-sdk-dynamodb', '~> 1.0'
|
15
|
+
gem 'aws-sdk-cloudwatch', '~> 1.0'
|
16
|
+
gem 'aws-sdk-s3', '~> 1.0'
|
17
|
+
end
|
18
|
+
|
19
|
+
group :gcp do
|
20
|
+
gem 'functions_framework', '~> 1.0'
|
21
|
+
gem 'google-cloud-firestore', '~> 2.0'
|
22
|
+
gem 'google-cloud-logging', '~> 2.0'
|
23
|
+
end
|
24
|
+
|
25
|
+
group :azure do
|
26
|
+
gem 'azure-storage-blob', '~> 2.0'
|
27
|
+
gem 'azure-cosmos', '~> 0.1'
|
28
|
+
end
|
29
|
+
|
30
|
+
group :development, :test do
|
31
|
+
gem 'rspec', '~> 3.11'
|
32
|
+
gem 'rack-test', '~> 2.0'
|
33
|
+
gem 'webmock', '~> 3.18'
|
34
|
+
gem 'vcr', '~> 6.1'
|
35
|
+
gem 'pry', '~> 0.14'
|
36
|
+
end
|
37
|
+
|
38
|
+
group :production do
|
39
|
+
gem 'newrelic_rpm', '~> 8.0' # For monitoring (optional)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Ruby version for serverless runtimes
|
43
|
+
ruby '3.2.0'
|