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,520 @@
|
|
1
|
+
# Serverless Deployment Guide for RapiTapir
|
2
|
+
|
3
|
+
This guide demonstrates how to deploy SinatraRapiTapir APIs as serverless functions across major cloud providers. Each example is production-ready and includes platform-specific optimizations.
|
4
|
+
|
5
|
+
## ๐ Overview
|
6
|
+
|
7
|
+
RapiTapir's SinatraRapiTapir base class is designed to work seamlessly in serverless environments while maintaining full type safety, automatic documentation, and all the features you love about RapiTapir.
|
8
|
+
|
9
|
+
### Key Benefits
|
10
|
+
- **๐ Zero Cold Start Impact**: Optimized initialization for fast function startup
|
11
|
+
- **๐ฐ Cost Effective**: Pay only for actual API requests
|
12
|
+
- **๐ Global Scale**: Deploy to edge locations worldwide
|
13
|
+
- **๐ Built-in Security**: Leverage cloud provider security features
|
14
|
+
- **๐ Native Monitoring**: Integrate with cloud monitoring services
|
15
|
+
|
16
|
+
## ๐ Quick Start Examples
|
17
|
+
|
18
|
+
### 1. AWS Lambda with API Gateway
|
19
|
+
|
20
|
+
**Deployment**: Uses AWS SAM for infrastructure-as-code
|
21
|
+
**Best For**: Enterprise applications, complex routing, DynamoDB integration
|
22
|
+
**Cold Start**: ~200ms with Ruby 3.2 runtime
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class MyAPI < SinatraRapiTapir
|
26
|
+
rapitapir do
|
27
|
+
info(title: 'AWS Lambda API', version: '1.0.0')
|
28
|
+
development_defaults!
|
29
|
+
end
|
30
|
+
|
31
|
+
endpoint(GET('/hello').query(:name, T.string).ok(T.hash({"message" => T.string})).build) do |inputs|
|
32
|
+
{ message: "Hello from Lambda, #{inputs[:name]}!" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def lambda_handler(event:, context:)
|
37
|
+
# Convert API Gateway event to Rack format
|
38
|
+
# Process through SinatraRapiTapir
|
39
|
+
# Return API Gateway response
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
**Deploy**:
|
44
|
+
```bash
|
45
|
+
sam build
|
46
|
+
sam deploy --guided
|
47
|
+
```
|
48
|
+
|
49
|
+
### 2. Google Cloud Functions
|
50
|
+
|
51
|
+
**Deployment**: Uses Functions Framework for Ruby
|
52
|
+
**Best For**: Google Cloud ecosystem, Firestore integration, AI/ML workloads
|
53
|
+
**Cold Start**: ~300ms with Ruby 3.2 runtime
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
require 'functions_framework'
|
57
|
+
|
58
|
+
class MyAPI < SinatraRapiTapir
|
59
|
+
# API definition...
|
60
|
+
end
|
61
|
+
|
62
|
+
FunctionsFramework.http('my_api') do |request|
|
63
|
+
# Convert Cloud Functions request to Rack
|
64
|
+
# Process through SinatraRapiTapir
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
**Deploy**:
|
69
|
+
```bash
|
70
|
+
gcloud functions deploy my-api \
|
71
|
+
--runtime ruby32 \
|
72
|
+
--trigger-http \
|
73
|
+
--allow-unauthenticated
|
74
|
+
```
|
75
|
+
|
76
|
+
### 3. Azure Functions
|
77
|
+
|
78
|
+
**Deployment**: Uses Azure Functions Core Tools
|
79
|
+
**Best For**: Microsoft ecosystem, Cosmos DB integration, hybrid cloud
|
80
|
+
**Cold Start**: ~400ms with custom Ruby runtime
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class MyAPI < SinatraRapiTapir
|
84
|
+
# API definition...
|
85
|
+
end
|
86
|
+
|
87
|
+
def main(context, req)
|
88
|
+
# Convert Azure request to Rack
|
89
|
+
# Process through SinatraRapiTapir
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
**Deploy**:
|
94
|
+
```bash
|
95
|
+
func azure functionapp publish my-function-app
|
96
|
+
```
|
97
|
+
|
98
|
+
### 4. Vercel Edge Functions
|
99
|
+
|
100
|
+
**Deployment**: Git-based deployment with zero configuration
|
101
|
+
**Best For**: Frontend integration, global edge deployment, fast response times
|
102
|
+
**Cold Start**: ~50ms at edge locations
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class MyAPI < SinatraRapiTapir
|
106
|
+
# API definition...
|
107
|
+
end
|
108
|
+
|
109
|
+
def handler(request:, response:)
|
110
|
+
# Convert Vercel request to Rack
|
111
|
+
# Process through SinatraRapiTapir
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
**Deploy**:
|
116
|
+
```bash
|
117
|
+
vercel --prod
|
118
|
+
```
|
119
|
+
|
120
|
+
## ๐๏ธ Architecture Patterns
|
121
|
+
|
122
|
+
### Pattern 1: Microservices Architecture
|
123
|
+
|
124
|
+
Deploy separate functions for different API domains:
|
125
|
+
|
126
|
+
```
|
127
|
+
/api/users โ users_function (AWS Lambda)
|
128
|
+
/api/books โ books_function (AWS Lambda)
|
129
|
+
/api/orders โ orders_function (AWS Lambda)
|
130
|
+
```
|
131
|
+
|
132
|
+
**Benefits**: Independent scaling, isolated failures, team autonomy
|
133
|
+
**Trade-offs**: Increased complexity, potential latency between services
|
134
|
+
|
135
|
+
### Pattern 2: Monolithic Function
|
136
|
+
|
137
|
+
Deploy entire API as single function:
|
138
|
+
|
139
|
+
```
|
140
|
+
/api/* โ single_api_function (Google Cloud Functions)
|
141
|
+
```
|
142
|
+
|
143
|
+
**Benefits**: Simpler deployment, shared code, lower latency
|
144
|
+
**Trade-offs**: Larger function size, shared scaling limits
|
145
|
+
|
146
|
+
### Pattern 3: Edge-First API
|
147
|
+
|
148
|
+
Deploy lightweight API to edge with database fallback:
|
149
|
+
|
150
|
+
```
|
151
|
+
Edge (Vercel) โ Fast reads, cached responses
|
152
|
+
Origin (AWS) โ Complex operations, database writes
|
153
|
+
```
|
154
|
+
|
155
|
+
**Benefits**: Ultra-low latency, global distribution
|
156
|
+
**Trade-offs**: Data consistency challenges, increased complexity
|
157
|
+
|
158
|
+
## ๐ง Platform-Specific Optimizations
|
159
|
+
|
160
|
+
### AWS Lambda Optimizations
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
class OptimizedLambdaAPI < SinatraRapiTapir
|
164
|
+
# Use provisioned concurrency for predictable performance
|
165
|
+
configure do
|
166
|
+
set :environment, :production
|
167
|
+
set :sessions, false # Lambda doesn't persist sessions
|
168
|
+
set :static, false # No static files in Lambda
|
169
|
+
end
|
170
|
+
|
171
|
+
# Use DynamoDB for fast, serverless storage
|
172
|
+
endpoint(GET('/users/:id').build) do |inputs|
|
173
|
+
user = dynamodb.get_item(
|
174
|
+
table_name: 'users',
|
175
|
+
key: { id: inputs[:id] }
|
176
|
+
).item
|
177
|
+
user || halt(404)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
**Key Features**:
|
183
|
+
- Provisioned Concurrency: Eliminate cold starts for critical functions
|
184
|
+
- DynamoDB Integration: Native serverless database
|
185
|
+
- X-Ray Tracing: Built-in distributed tracing
|
186
|
+
- VPC Support: Access private resources securely
|
187
|
+
|
188
|
+
### Google Cloud Functions Optimizations
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
class OptimizedCloudFunctionAPI < SinatraRapiTapir
|
192
|
+
# Use Firestore for real-time, scalable storage
|
193
|
+
configure do
|
194
|
+
set :protection, except: [:json_csrf] # Cloud Functions handles security
|
195
|
+
end
|
196
|
+
|
197
|
+
endpoint(GET('/books').build) do
|
198
|
+
firestore = Google::Cloud::Firestore.new
|
199
|
+
books = firestore.collection('books').get
|
200
|
+
books.map(&:data)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
**Key Features**:
|
206
|
+
- Firestore Integration: Real-time NoSQL database
|
207
|
+
- Cloud IAM: Fine-grained access control
|
208
|
+
- Cloud Monitoring: Native observability
|
209
|
+
- Automatic Scaling: Zero to billions of requests
|
210
|
+
|
211
|
+
### Azure Functions Optimizations
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
class OptimizedAzureFunctionAPI < SinatraRapiTapir
|
215
|
+
# Use Cosmos DB for globally distributed data
|
216
|
+
configure do
|
217
|
+
set :show_exceptions, false # Azure handles error pages
|
218
|
+
end
|
219
|
+
|
220
|
+
endpoint(POST('/orders').build) do |inputs|
|
221
|
+
cosmos_db.create_document(
|
222
|
+
collection_link: 'orders',
|
223
|
+
document: inputs[:body]
|
224
|
+
)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
**Key Features**:
|
230
|
+
- Cosmos DB: Multi-model, globally distributed database
|
231
|
+
- Application Insights: Advanced monitoring and diagnostics
|
232
|
+
- Service Bus: Reliable message queuing
|
233
|
+
- Key Vault: Secure secrets management
|
234
|
+
|
235
|
+
### Vercel Edge Optimizations
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
class OptimizedVercelAPI < SinatraRapiTapir
|
239
|
+
# Optimize for edge performance
|
240
|
+
configure do
|
241
|
+
set :static, false
|
242
|
+
set :sessions, false
|
243
|
+
end
|
244
|
+
|
245
|
+
# Use edge caching for fast responses
|
246
|
+
endpoint(GET('/products/:id').build) do |inputs|
|
247
|
+
cache_control 'public, max-age=300, s-maxage=3600'
|
248
|
+
Product.find(inputs[:id])
|
249
|
+
end
|
250
|
+
end
|
251
|
+
```
|
252
|
+
|
253
|
+
**Key Features**:
|
254
|
+
- Edge Caching: Responses cached at 100+ global locations
|
255
|
+
- Zero Configuration: Git-based deployment
|
256
|
+
- Preview Deployments: Test every pull request
|
257
|
+
- Fast Builds: Optimized for frontend workflows
|
258
|
+
|
259
|
+
## ๐ Performance Benchmarks
|
260
|
+
|
261
|
+
| Platform | Cold Start | Warm Response | Max Concurrency | Cost (1M requests) |
|
262
|
+
|----------|------------|---------------|-----------------|-------------------|
|
263
|
+
| AWS Lambda | 200ms | 5ms | 1000/region | $0.20 |
|
264
|
+
| Google Cloud Functions | 300ms | 8ms | 3000/region | $0.40 |
|
265
|
+
| Azure Functions | 400ms | 10ms | 200/region | $0.20 |
|
266
|
+
| Vercel Edge | 50ms | 2ms | Global | $0.12 |
|
267
|
+
|
268
|
+
*Benchmarks based on Ruby 3.2 runtime with 512MB memory*
|
269
|
+
|
270
|
+
## ๐ก๏ธ Security Best Practices
|
271
|
+
|
272
|
+
### 1. Authentication & Authorization
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
class SecureServerlessAPI < SinatraRapiTapir
|
276
|
+
rapitapir do
|
277
|
+
# Use cloud provider authentication
|
278
|
+
bearer_auth :jwt, realm: 'API'
|
279
|
+
|
280
|
+
# AWS: Use Cognito or API Gateway authorizers
|
281
|
+
# GCP: Use Identity and Access Management
|
282
|
+
# Azure: Use Active Directory
|
283
|
+
# Vercel: Use Auth0 or similar
|
284
|
+
end
|
285
|
+
|
286
|
+
endpoint(
|
287
|
+
GET('/secure-data')
|
288
|
+
.bearer_auth(scopes: ['read:data'])
|
289
|
+
.build
|
290
|
+
) do
|
291
|
+
# Access control automatically enforced
|
292
|
+
SecureData.all
|
293
|
+
end
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
297
|
+
### 2. Input Validation
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
# RapiTapir's type system provides automatic validation
|
301
|
+
endpoint(
|
302
|
+
POST('/users')
|
303
|
+
.body(T.hash({
|
304
|
+
"email" => T.email, # Validates email format
|
305
|
+
"age" => T.integer(minimum: 18), # Validates age >= 18
|
306
|
+
"phone" => T.string(pattern: /^\+\d+/) # Validates phone format
|
307
|
+
}))
|
308
|
+
.build
|
309
|
+
) do |inputs|
|
310
|
+
# inputs[:body] is guaranteed to be valid
|
311
|
+
User.create(inputs[:body])
|
312
|
+
end
|
313
|
+
```
|
314
|
+
|
315
|
+
### 3. Error Handling
|
316
|
+
|
317
|
+
```ruby
|
318
|
+
class RobustServerlessAPI < SinatraRapiTapir
|
319
|
+
# Global error handling
|
320
|
+
error StandardError do |e|
|
321
|
+
logger.error("Unexpected error: #{e.message}")
|
322
|
+
|
323
|
+
# Don't expose internal errors
|
324
|
+
{ error: 'Internal server error' }.to_json
|
325
|
+
end
|
326
|
+
|
327
|
+
# Specific error handling
|
328
|
+
error ValidationError do |e|
|
329
|
+
status 400
|
330
|
+
{ error: 'Validation failed', details: e.errors }.to_json
|
331
|
+
end
|
332
|
+
end
|
333
|
+
```
|
334
|
+
|
335
|
+
## ๐ Monitoring & Observability
|
336
|
+
|
337
|
+
### CloudWatch (AWS)
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
class MonitoredLambdaAPI < SinatraRapiTapir
|
341
|
+
# Custom metrics
|
342
|
+
endpoint(GET('/books').build) do
|
343
|
+
start_time = Time.now
|
344
|
+
|
345
|
+
books = Book.all
|
346
|
+
|
347
|
+
# Send custom metric to CloudWatch
|
348
|
+
cloudwatch.put_metric_data(
|
349
|
+
namespace: 'BookAPI',
|
350
|
+
metric_data: [{
|
351
|
+
metric_name: 'BookQueryDuration',
|
352
|
+
value: (Time.now - start_time) * 1000,
|
353
|
+
unit: 'Milliseconds'
|
354
|
+
}]
|
355
|
+
)
|
356
|
+
|
357
|
+
books.map(&:to_h)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
362
|
+
### Google Cloud Monitoring
|
363
|
+
|
364
|
+
```ruby
|
365
|
+
class MonitoredCloudFunctionAPI < SinatraRapiTapir
|
366
|
+
# Structured logging for Cloud Logging
|
367
|
+
endpoint(GET('/users').build) do
|
368
|
+
logger.info({
|
369
|
+
message: 'Fetching users',
|
370
|
+
user_count: User.count,
|
371
|
+
timestamp: Time.now.iso8601
|
372
|
+
}.to_json)
|
373
|
+
|
374
|
+
User.all.map(&:to_h)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
```
|
378
|
+
|
379
|
+
### Application Insights (Azure)
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
class MonitoredAzureFunctionAPI < SinatraRapiTapir
|
383
|
+
# Track dependencies and exceptions
|
384
|
+
endpoint(GET('/orders').build) do
|
385
|
+
telemetry_client.track_dependency(
|
386
|
+
name: 'Database Query',
|
387
|
+
type: 'SQL',
|
388
|
+
data: 'SELECT * FROM orders',
|
389
|
+
duration: 0.1,
|
390
|
+
success: true
|
391
|
+
)
|
392
|
+
|
393
|
+
Order.all.map(&:to_h)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
```
|
397
|
+
|
398
|
+
## ๐ Deployment Automation
|
399
|
+
|
400
|
+
### GitHub Actions for Multi-Cloud
|
401
|
+
|
402
|
+
```yaml
|
403
|
+
name: Deploy Serverless API
|
404
|
+
|
405
|
+
on:
|
406
|
+
push:
|
407
|
+
branches: [main]
|
408
|
+
|
409
|
+
jobs:
|
410
|
+
deploy-aws:
|
411
|
+
runs-on: ubuntu-latest
|
412
|
+
steps:
|
413
|
+
- uses: actions/checkout@v3
|
414
|
+
- name: Deploy to AWS Lambda
|
415
|
+
run: sam deploy --no-confirm-changeset
|
416
|
+
|
417
|
+
deploy-gcp:
|
418
|
+
runs-on: ubuntu-latest
|
419
|
+
steps:
|
420
|
+
- uses: actions/checkout@v3
|
421
|
+
- name: Deploy to Google Cloud Functions
|
422
|
+
run: gcloud functions deploy my-api --source .
|
423
|
+
|
424
|
+
deploy-vercel:
|
425
|
+
runs-on: ubuntu-latest
|
426
|
+
steps:
|
427
|
+
- uses: actions/checkout@v3
|
428
|
+
- uses: amondnet/vercel-action@v20
|
429
|
+
with:
|
430
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
431
|
+
```
|
432
|
+
|
433
|
+
## ๐งช Testing Serverless APIs
|
434
|
+
|
435
|
+
### Local Development
|
436
|
+
|
437
|
+
```ruby
|
438
|
+
# test/serverless_test.rb
|
439
|
+
require 'minitest/autorun'
|
440
|
+
require_relative '../aws_lambda_example'
|
441
|
+
|
442
|
+
class ServerlessAPITest < Minitest::Test
|
443
|
+
def setup
|
444
|
+
@app = BookAPILambda.new
|
445
|
+
end
|
446
|
+
|
447
|
+
def test_lambda_handler
|
448
|
+
event = {
|
449
|
+
'httpMethod' => 'GET',
|
450
|
+
'path' => '/health',
|
451
|
+
'headers' => {},
|
452
|
+
'body' => nil
|
453
|
+
}
|
454
|
+
|
455
|
+
context = OpenStruct.new(aws_request_id: 'test-123')
|
456
|
+
|
457
|
+
response = lambda_handler(event: event, context: context)
|
458
|
+
|
459
|
+
assert_equal 200, response[:statusCode]
|
460
|
+
assert_includes response[:body], 'healthy'
|
461
|
+
end
|
462
|
+
|
463
|
+
def test_book_creation
|
464
|
+
post '/books', {
|
465
|
+
title: 'Test Book',
|
466
|
+
author: 'Test Author'
|
467
|
+
}.to_json, 'CONTENT_TYPE' => 'application/json'
|
468
|
+
|
469
|
+
assert_equal 201, last_response.status
|
470
|
+
|
471
|
+
book = JSON.parse(last_response.body)
|
472
|
+
assert_equal 'Test Book', book['title']
|
473
|
+
end
|
474
|
+
end
|
475
|
+
```
|
476
|
+
|
477
|
+
### Integration Testing
|
478
|
+
|
479
|
+
```bash
|
480
|
+
# Test against actual deployed functions
|
481
|
+
curl -X GET "https://api.example.com/health" \
|
482
|
+
-H "Authorization: Bearer $API_TOKEN"
|
483
|
+
|
484
|
+
# Load testing with Artillery
|
485
|
+
artillery quick --count 100 --num 10 "https://api.example.com/books"
|
486
|
+
```
|
487
|
+
|
488
|
+
## ๐ฏ Best Practices Summary
|
489
|
+
|
490
|
+
### โ
Do's
|
491
|
+
|
492
|
+
1. **Minimize Cold Starts**: Keep function size small, use provisioned concurrency
|
493
|
+
2. **Leverage Native Services**: Use cloud provider databases and services
|
494
|
+
3. **Implement Proper Logging**: Use structured logging for better observability
|
495
|
+
4. **Set Up Monitoring**: Monitor performance, errors, and business metrics
|
496
|
+
5. **Use Type Safety**: Leverage RapiTapir's validation for robust APIs
|
497
|
+
6. **Handle Errors Gracefully**: Don't expose internal errors to clients
|
498
|
+
7. **Optimize for Platform**: Use platform-specific features and optimizations
|
499
|
+
|
500
|
+
### โ Don'ts
|
501
|
+
|
502
|
+
1. **Don't Store State**: Functions are stateless, use external storage
|
503
|
+
2. **Don't Ignore Cold Starts**: Design for variable response times
|
504
|
+
3. **Don't Over-Engineer**: Start simple, optimize based on real usage
|
505
|
+
4. **Don't Forget Security**: Always validate inputs and authenticate requests
|
506
|
+
5. **Don't Ignore Costs**: Monitor usage and optimize for cost efficiency
|
507
|
+
6. **Don't Assume Reliability**: Implement retries and circuit breakers
|
508
|
+
7. **Don't Skip Testing**: Test locally and with real cloud resources
|
509
|
+
|
510
|
+
## ๐ Additional Resources
|
511
|
+
|
512
|
+
- [AWS Lambda Ruby Runtime Guide](https://docs.aws.amazon.com/lambda/latest/dg/lambda-ruby.html)
|
513
|
+
- [Google Cloud Functions Ruby Quickstart](https://cloud.google.com/functions/docs/quickstart-ruby)
|
514
|
+
- [Azure Functions Custom Handlers](https://docs.microsoft.com/en-us/azure/azure-functions/functions-custom-handlers)
|
515
|
+
- [Vercel Ruby Runtime Documentation](https://vercel.com/docs/runtimes#ruby)
|
516
|
+
- [RapiTapir Documentation](../README.md)
|
517
|
+
|
518
|
+
---
|
519
|
+
|
520
|
+
**Ready to deploy your first serverless RapiTapir API?** Choose your platform and follow the example above! ๐
|