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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -7
  3. data/.rubocop_todo.yml +83 -0
  4. data/README.md +1319 -235
  5. data/RUBY_WEEKLY_LAUNCH_POST.md +219 -0
  6. data/docs/RAILS_INTEGRATION_IMPLEMENTATION.md +209 -0
  7. data/docs/SINATRA_EXTENSION.md +399 -348
  8. data/docs/STRICT_VALIDATION.md +229 -0
  9. data/docs/VALIDATION_IMPROVEMENTS.md +218 -0
  10. data/docs/ai-integration-plan.md +112 -0
  11. data/docs/auto-derivation.md +505 -92
  12. data/docs/endpoint-definition.md +536 -129
  13. data/docs/n8n-integration.md +212 -0
  14. data/docs/observability.md +810 -500
  15. data/docs/using-mcp.md +93 -0
  16. data/examples/ai/knowledge_base_rag.rb +83 -0
  17. data/examples/ai/user_management_mcp.rb +92 -0
  18. data/examples/ai/user_validation_llm.rb +187 -0
  19. data/examples/rails/RAILS_8_GUIDE.md +165 -0
  20. data/examples/rails/RAILS_LOADING_FIX.rb +35 -0
  21. data/examples/rails/README.md +497 -0
  22. data/examples/rails/comprehensive_test.rb +91 -0
  23. data/examples/rails/config/routes.rb +48 -0
  24. data/examples/rails/debug_controller.rb +63 -0
  25. data/examples/rails/detailed_test.rb +46 -0
  26. data/examples/rails/enhanced_users_controller.rb +278 -0
  27. data/examples/rails/final_server_test.rb +50 -0
  28. data/examples/rails/hello_world_app.rb +116 -0
  29. data/examples/rails/hello_world_controller.rb +186 -0
  30. data/examples/rails/hello_world_routes.rb +28 -0
  31. data/examples/rails/rails8_minimal_demo.rb +132 -0
  32. data/examples/rails/rails8_simple_demo.rb +140 -0
  33. data/examples/rails/rails8_working_demo.rb +255 -0
  34. data/examples/rails/real_world_blog_api.rb +510 -0
  35. data/examples/rails/server_test.rb +46 -0
  36. data/examples/rails/test_direct_processing.rb +41 -0
  37. data/examples/rails/test_hello_world.rb +80 -0
  38. data/examples/rails/test_rails_integration.rb +54 -0
  39. data/examples/rails/traditional_app/Gemfile +37 -0
  40. data/examples/rails/traditional_app/README.md +265 -0
  41. data/examples/rails/traditional_app/app/controllers/api/v1/posts_controller.rb +254 -0
  42. data/examples/rails/traditional_app/app/controllers/api/v1/users_controller.rb +220 -0
  43. data/examples/rails/traditional_app/app/controllers/application_controller.rb +86 -0
  44. data/examples/rails/traditional_app/app/controllers/application_controller_simplified.rb +87 -0
  45. data/examples/rails/traditional_app/app/controllers/documentation_controller.rb +149 -0
  46. data/examples/rails/traditional_app/app/controllers/health_controller.rb +42 -0
  47. data/examples/rails/traditional_app/config/routes.rb +25 -0
  48. data/examples/rails/traditional_app/config/routes_best_practice.rb +25 -0
  49. data/examples/rails/traditional_app/config/routes_simplified.rb +36 -0
  50. data/examples/rails/traditional_app_runnable.rb +406 -0
  51. data/examples/rails/users_controller.rb +4 -1
  52. data/examples/serverless/Gemfile +43 -0
  53. data/examples/serverless/QUICKSTART.md +331 -0
  54. data/examples/serverless/README.md +520 -0
  55. data/examples/serverless/aws_lambda_example.rb +307 -0
  56. data/examples/serverless/aws_sam_template.yaml +215 -0
  57. data/examples/serverless/azure_functions_example.rb +407 -0
  58. data/examples/serverless/deploy.rb +204 -0
  59. data/examples/serverless/gcp_cloud_functions_example.rb +367 -0
  60. data/examples/serverless/gcp_function.yaml +23 -0
  61. data/examples/serverless/host.json +24 -0
  62. data/examples/serverless/package.json +32 -0
  63. data/examples/serverless/spec/aws_lambda_spec.rb +196 -0
  64. data/examples/serverless/spec/spec_helper.rb +89 -0
  65. data/examples/serverless/vercel.json +31 -0
  66. data/examples/serverless/vercel_example.rb +404 -0
  67. data/examples/strict_validation_examples.rb +104 -0
  68. data/examples/validation_error_examples.rb +173 -0
  69. data/lib/rapitapir/ai/llm_instruction.rb +456 -0
  70. data/lib/rapitapir/ai/mcp.rb +134 -0
  71. data/lib/rapitapir/ai/rag.rb +287 -0
  72. data/lib/rapitapir/ai/rag_middleware.rb +147 -0
  73. data/lib/rapitapir/auth/oauth2.rb +43 -57
  74. data/lib/rapitapir/cli/command.rb +362 -2
  75. data/lib/rapitapir/cli/mcp_export.rb +18 -0
  76. data/lib/rapitapir/cli/validator.rb +2 -6
  77. data/lib/rapitapir/core/endpoint.rb +59 -6
  78. data/lib/rapitapir/core/enhanced_endpoint.rb +2 -6
  79. data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +53 -0
  80. data/lib/rapitapir/endpoint_registry.rb +47 -0
  81. data/lib/rapitapir/observability/health_check.rb +4 -4
  82. data/lib/rapitapir/observability/logging.rb +10 -10
  83. data/lib/rapitapir/schema.rb +2 -2
  84. data/lib/rapitapir/server/rack_adapter.rb +1 -3
  85. data/lib/rapitapir/server/rails/configuration.rb +77 -0
  86. data/lib/rapitapir/server/rails/controller_base.rb +185 -0
  87. data/lib/rapitapir/server/rails/documentation_helpers.rb +76 -0
  88. data/lib/rapitapir/server/rails/resource_builder.rb +181 -0
  89. data/lib/rapitapir/server/rails/routes.rb +114 -0
  90. data/lib/rapitapir/server/rails_adapter.rb +10 -3
  91. data/lib/rapitapir/server/rails_adapter_class.rb +1 -3
  92. data/lib/rapitapir/server/rails_controller.rb +1 -3
  93. data/lib/rapitapir/server/rails_integration.rb +67 -0
  94. data/lib/rapitapir/server/rails_response_handler.rb +16 -3
  95. data/lib/rapitapir/server/sinatra_adapter.rb +29 -5
  96. data/lib/rapitapir/server/sinatra_integration.rb +4 -4
  97. data/lib/rapitapir/sinatra/extension.rb +2 -2
  98. data/lib/rapitapir/sinatra/oauth2_helpers.rb +34 -40
  99. data/lib/rapitapir/types/array.rb +4 -0
  100. data/lib/rapitapir/types/auto_derivation.rb +4 -18
  101. data/lib/rapitapir/types/datetime.rb +1 -3
  102. data/lib/rapitapir/types/float.rb +2 -6
  103. data/lib/rapitapir/types/hash.rb +40 -2
  104. data/lib/rapitapir/types/integer.rb +4 -12
  105. data/lib/rapitapir/types/object.rb +6 -2
  106. data/lib/rapitapir/types.rb +6 -2
  107. data/lib/rapitapir/version.rb +1 -1
  108. data/lib/rapitapir.rb +5 -3
  109. data/rapitapir.gemspec +7 -5
  110. metadata +116 -16
data/README.md CHANGED
@@ -1,278 +1,824 @@
1
- # RapiTapir## ๐Ÿ†• What's New
1
+ # RapiTapir
2
2
 
3
- - **โœจ - **๐Ÿ“ Type Shortcuts**: Global `T.string`, `T.integer`, etc. (automatically available!)
4
- - **๐Ÿ”„ GitHub Pages**: Modern documentation deployment with GitHub Actionsean Base Class**: `class MyAPI < SinatraRapiTapir` - the simplest way to create APIs
5
- - **๐ŸŽฏ Enhanced HTTP DSL**: Built-in GET, POST, PUT, DELETE methods with fluent chaining
6
- - **๐Ÿ”ง Zero Boilerplate**: Automatic extension registration and feature setup
7
- - ๐Ÿ“ **Type Shortcuts**: Clean syntax with global `T` constant (automatic - no setup needed!)
8
- - **๐Ÿ“š GitHub Pages Ready**: Modern documentation deployment with GitHub Actions
9
- - **๐Ÿงช Comprehensive Tests**: 470 tests passing with 70% coverage modern Ruby library for building type-safe HTTP APIs with automatic OpenAPI documentation**
10
-
11
- [![Tests](https://img.shields.io/badge/tests-470%20passing-brightgreen)](spec/)
12
- [![Coverage](https://img.shields.io/badge/coverage-70.13%25-green)](coverage/)
3
+ [![Tests](https://img.shields.io/badge/tests-643%20passing-brightgreen)](spec/)
4
+ [![Coverage](https://img.shields.io/badge/coverage-67.67%25-green)](coverage/)
13
5
  [![Ruby](https://img.shields.io/badge/ruby-3.1%2B-red)](Gemfile)
14
6
  [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
+ [![RuboCop](https://img.shields.io/badge/code%20style-rubocop-brightgreen)](https://github.com/rubocop/rubocop)
8
+ [![AI Ready](https://img.shields.io/badge/AI-LLM%20%7C%20RAG%20%7C%20MCP-purple)](lib/rapitapir/ai/)
15
9
 
16
- **RapiTapir ๐Ÿฆ™** combines the expressiveness of Ruby with the safety of strong typing to create APIs that are both powerful and reliable. Define your endpoints once with our fluent DSL, and get automatic validation, documentation, and client generation.
10
+ **RapiTapir ๐Ÿฆ™** combines the expressiveness of Ruby with the safety of strong typing to create APIs that are both powerful and reliable. Define your endpoints once with our fluent DSL, and get automatic validation, documentation, client generation, and AI-powered features.
17
11
 
18
- ## ๐Ÿ†• What's New
12
+ ## ๐Ÿš€ Latest Features (v2.0)
19
13
 
20
- - **โœจ Clean Base Class**: `class MyAPI < SinatraRapiTapir` - the simplest way to create APIs
21
- - **๐ŸŽฏ Enhanced HTTP DSL**: Built-in GET, POST, PUT, DELETE methods with fluent chaining
22
- - **๐Ÿ”ง Zero Boilerplate**: Automatic extension registration and feature setup
23
- - **๏ฟฝ Type Shortcuts**: Use `T.string` instead of `RapiTapir::Types.string` for cleaner code
24
- - **๏ฟฝ๐Ÿ“š GitHub Pages Ready**: Modern documentation deployment with GitHub Actions
25
- - **๐Ÿงช Comprehensive Tests**: 470 tests passing with 70% coverage
14
+ - **๐Ÿค– AI Integration**: Built-in LLM instruction generation, RAG pipelines, and MCP export
15
+ - **โœจ SinatraRapiTapir Base Class**: `class MyAPI < SinatraRapiTapir` - zero-boilerplate API creation
16
+ - **๐ŸŽฏ Enhanced HTTP DSL**: Native GET, POST, PUT, DELETE methods with fluent chaining
17
+ - **๐Ÿ”ง Zero Configuration**: Automatic extension registration and intelligent defaults
18
+ - **โšก T Shortcut**: Use `T.string` instead of `RapiTapir::Types.string` everywhere
19
+ - **๐Ÿ“š GitHub Pages Ready**: Modern documentation deployment with GitHub Actions
20
+ - **๐Ÿ” CLI Toolkit**: Complete command-line interface for generation, validation, and serving
21
+ - **๐Ÿงช Comprehensive Tests**: 643 tests passing with 67.67% coverage
26
22
 
27
23
  ## โœจ Why RapiTapir?
28
24
 
29
- - **๐Ÿ”’ Type Safety**: Strong typing for inputs and outputs with runtime validation
25
+ - **๐Ÿ”’ Type Safety**: Strong typing with runtime validation and compile-time confidence
30
26
  - **๐Ÿ“– Auto Documentation**: OpenAPI 3.0 specs generated automatically from your code
31
27
  - **๐Ÿš€ Framework Agnostic**: Works with Sinatra, Rails, and any Rack-based framework
32
28
  - **๐Ÿ›ก๏ธ Production Ready**: Built-in security, observability, and authentication features
33
29
  - **๐Ÿ’Ž Ruby Native**: Designed specifically for Ruby developers who love clean, readable code
34
30
  - **๐Ÿ”ง Zero Config**: Get started in minutes with sensible defaults
35
- - **โœจ Clean Syntax**: Elegant base class: `class MyAPI < SinatraRapiTapir`
36
- - **๐ŸŽฏ Enhanced DSL**: Built-in HTTP verb methods (GET, POST, PUT, etc.)
37
- - **๏ฟฝ Type Shortcuts**: Clean type syntax with `T.string`, `T.integer`, etc.
38
- - **๏ฟฝ๐Ÿ”„ GitHub Pages**: Modern documentation deployment with GitHub Actions
31
+ - **๐Ÿค– AI Powered**: Built-in LLM instruction generation, RAG pipelines, and MCP export
32
+ - **โšก Enhanced DSL**: Clean syntax with `T.string`, HTTP verbs, and resource builders
33
+ - **๐Ÿ”„ CLI Toolkit**: Complete command-line interface for all development tasks
39
34
 
40
35
  ## ๐Ÿš€ Quick Start
41
36
 
42
- ### Installation
43
-
44
- Add to your Gemfile:
37
+ ### Minimal Example (30 seconds)
45
38
 
46
39
  ```ruby
47
- gem 'rapitapir'
40
+ require 'rapitapir'
41
+
42
+ class HelloAPI < SinatraRapiTapir
43
+ # That's it! Zero configuration needed.
44
+ endpoint(
45
+ GET('/hello')
46
+ .query(:name, T.string, description: 'Your name')
47
+ .ok(T.hash({ "message" => T.string }))
48
+ .build
49
+ ) { |inputs| { message: "Hello, #{inputs[:name]}!" } }
50
+
51
+ run! if __FILE__ == $0
52
+ end
48
53
  ```
49
54
 
50
- ### Basic Sinatra Example
55
+ **Start server**: `ruby hello_api.rb`
56
+ **Try it**: `curl "http://localhost:4567/hello?name=World"`
57
+ **Docs**: `http://localhost:4567/docs`
58
+
59
+ ### Complete Example (5 minutes)
51
60
 
52
61
  ```ruby
53
- require 'rapitapir' # Only one require needed!
62
+ require 'rapitapir'
54
63
 
55
64
  class BookAPI < SinatraRapiTapir
56
65
  # Configure API information
57
66
  rapitapir do
58
67
  info(
59
- title: 'Book API',
60
- description: 'A simple book management API',
61
- version: '1.0.0'
68
+ title: 'Book Management API',
69
+ description: 'A comprehensive book management system with AI features',
70
+ version: '2.0.0'
62
71
  )
63
- development_defaults! # Auto CORS, docs, health checks
72
+ development_defaults! # Auto CORS, docs, health checks, metrics
64
73
  end
65
74
 
66
- # Define your data schema with T shortcut (globally available!)
75
+ # Define schemas using T shortcut (available everywhere!)
67
76
  BOOK_SCHEMA = T.hash({
68
77
  "id" => T.integer,
69
78
  "title" => T.string(min_length: 1, max_length: 255),
70
79
  "author" => T.string(min_length: 1),
71
80
  "published" => T.boolean,
72
- "isbn" => T.optional(T.string),
73
- "pages" => T.optional(T.integer(minimum: 1))
81
+ "isbn" => T.optional(T.string(pattern: /^\d{13}$/)),
82
+ "pages" => T.optional(T.integer(minimum: 1)),
83
+ "tags" => T.optional(T.array(T.string)),
84
+ "metadata" => T.optional(T.hash({
85
+ "genre" => T.string,
86
+ "rating" => T.float(minimum: 0, maximum: 5)
87
+ }))
74
88
  })
75
89
 
76
- # Define endpoints with the elegant resource DSL and enhanced HTTP verbs
90
+ # RESTful resource with full CRUD
77
91
  api_resource '/books', schema: BOOK_SCHEMA do
78
92
  crud do
79
- index { Book.all }
80
-
81
- show do |inputs|
82
- Book.find(inputs[:id]) || halt(404, { error: 'Book not found' }.to_json)
93
+ index do
94
+ # Automatic pagination and filtering
95
+ books = Book.all
96
+ books = books.where(published: true) if params[:published] == 'true'
97
+ books.limit(params[:limit] || 50).map(&:to_h)
83
98
  end
84
99
 
100
+ show { |inputs| Book.find(inputs[:id])&.to_h || halt(404) }
101
+
85
102
  create do |inputs|
86
- Book.create(inputs[:body])
103
+ book = Book.create(inputs[:body])
104
+ status 201
105
+ book.to_h
87
106
  end
107
+
108
+ update { |inputs| Book.update(inputs[:id], inputs[:body]).to_h }
109
+ destroy { |inputs| Book.delete(inputs[:id]); status 204 }
88
110
  end
89
111
 
90
- # Custom endpoint using enhanced DSL
112
+ # Custom endpoints with full type safety
91
113
  custom :get, 'featured' do
92
- Book.where(featured: true)
114
+ Book.where(featured: true).map(&:to_h)
115
+ end
116
+
117
+ custom :post, ':id/reviews' do |inputs|
118
+ book = Book.find(inputs[:id])
119
+ review = book.add_review(inputs[:body])
120
+ status 201
121
+ review.to_h
93
122
  end
94
123
  end
95
124
 
96
- # Alternative endpoint definition using enhanced HTTP verb DSL
125
+ # Advanced search with AI-powered features
97
126
  endpoint(
98
127
  GET('/books/search')
99
128
  .query(:q, T.string(min_length: 1), description: 'Search query')
100
129
  .query(:limit, T.optional(T.integer(minimum: 1, maximum: 100)), description: 'Results limit')
101
- .summary('Search books')
102
- .description('Search books by title or author')
103
- .tags('Search')
104
- .ok(T.array(BOOK_SCHEMA))
105
- .bad_request(T.hash({ "error" => T.string }), description: 'Invalid search parameters')
130
+ .query(:ai_powered, T.optional(T.boolean), description: 'Use AI-enhanced search')
131
+ .summary('Search books with optional AI enhancement')
132
+ .description('Search books by title, author, or content with optional AI semantic search')
133
+ .tags('Search', 'AI')
134
+ .ok(T.hash({
135
+ "books" => T.array(BOOK_SCHEMA),
136
+ "total" => T.integer,
137
+ "ai_enhanced" => T.boolean,
138
+ "suggestions" => T.optional(T.array(T.string))
139
+ }))
140
+ .bad_request(T.hash({ "error" => T.string }))
141
+ .enable_rag # AI-powered retrieval augmented generation
142
+ .enable_mcp # Export to Model Context Protocol
106
143
  .build
107
144
  ) do |inputs|
108
145
  query = inputs[:q]
109
146
  limit = inputs[:limit] || 20
147
+ ai_powered = inputs[:ai_powered] || false
148
+
149
+ if ai_powered
150
+ # Use AI-enhanced search
151
+ results = BookSearchService.ai_search(query, limit: limit)
152
+ suggestions = BookSearchService.get_suggestions(query)
153
+ else
154
+ results = Book.search(query).limit(limit)
155
+ suggestions = nil
156
+ end
110
157
 
111
- books = Book.search(query).limit(limit)
112
- books.map(&:to_h)
158
+ {
159
+ books: results.map(&:to_h),
160
+ total: results.count,
161
+ ai_enhanced: ai_powered,
162
+ suggestions: suggestions
163
+ }
113
164
  end
114
165
 
115
166
  run! if __FILE__ == $0
116
167
  end
117
168
  ```
118
169
 
119
- Start your server and visit:
120
- - **๐Ÿ“– Interactive Documentation**: `http://localhost:4567/docs`
121
- - **๐Ÿ“‹ OpenAPI Specification**: `http://localhost:4567/openapi.json`
170
+ **Start and explore**:
171
+ - **Server**: `ruby book_api.rb`
172
+ - **Interactive Docs**: `http://localhost:4567/docs`
173
+ - **OpenAPI Spec**: `http://localhost:4567/openapi.json`
174
+ - **Health Check**: `http://localhost:4567/health`
175
+ ## ๐Ÿ—๏ธ Advanced Features
122
176
 
123
- That's it! You now have a fully documented, type-safe API with interactive documentation.
177
+ ### ๐Ÿค– AI-Powered APIs
178
+
179
+ ```ruby
180
+ class AIBookAPI < SinatraRapiTapir
181
+ rapitapir do
182
+ info(title: 'AI-Powered Book API', version: '2.0.0')
183
+ development_defaults!
184
+ end
185
+
186
+ # Configure AI providers
187
+ configure do
188
+ set :openai_api_key, ENV['OPENAI_API_KEY']
189
+ set :rag_backend, :memory # or :elasticsearch, :postgresql
190
+ end
191
+
192
+ # AI-enhanced book recommendations
193
+ endpoint(
194
+ GET('/books/recommendations')
195
+ .query(:user_id, T.integer, description: 'User ID for personalization')
196
+ .query(:preferences, T.optional(T.string), description: 'User preferences text')
197
+ .summary('Get AI-powered book recommendations')
198
+ .description('Uses LLM to generate personalized book recommendations')
199
+ .tags('AI', 'Recommendations')
200
+ .ok(T.hash({
201
+ "recommendations" => T.array(BOOK_SCHEMA),
202
+ "reasoning" => T.string,
203
+ "confidence" => T.float(minimum: 0, maximum: 1)
204
+ }))
205
+ .enable_llm_instructions(purpose: :completion) # Generate LLM instructions
206
+ .enable_rag(
207
+ retrieval_backend: :memory,
208
+ llm_provider: :openai,
209
+ context_window: 4000
210
+ )
211
+ .enable_mcp # Export for AI agent consumption
212
+ .build
213
+ ) do |inputs|
214
+ user = User.find(inputs[:user_id])
215
+ preferences = inputs[:preferences] || user.inferred_preferences
216
+
217
+ # RAG pipeline automatically injects relevant context
218
+ recommendations = AIRecommendationService.generate(
219
+ user: user,
220
+ preferences: preferences,
221
+ context: rag_context # Automatically provided by RAG middleware
222
+ )
223
+
224
+ {
225
+ recommendations: recommendations[:books],
226
+ reasoning: recommendations[:explanation],
227
+ confidence: recommendations[:confidence_score]
228
+ }
229
+ end
230
+
231
+ # LLM instruction generation endpoint
232
+ endpoint(
233
+ GET('/ai/instructions')
234
+ .query(:endpoint_id, T.string, description: 'Endpoint ID to generate instructions for')
235
+ .query(:purpose, T.string(enum: %w[validation transformation analysis documentation testing completion]),
236
+ description: 'Instruction purpose')
237
+ .summary('Generate LLM instructions for endpoints')
238
+ .ok(T.hash({
239
+ "instructions" => T.string,
240
+ "metadata" => T.hash({
241
+ "endpoint" => T.string,
242
+ "purpose" => T.string,
243
+ "generated_at" => T.datetime
244
+ })
245
+ }))
246
+ .build
247
+ ) do |inputs|
248
+ generator = RapiTapir::AI::LLMInstruction::Generator.new
249
+ endpoint = find_endpoint(inputs[:endpoint_id])
250
+
251
+ instructions = generator.generate_instructions(
252
+ endpoint: endpoint,
253
+ purpose: inputs[:purpose].to_sym
254
+ )
255
+
256
+ {
257
+ instructions: instructions,
258
+ metadata: {
259
+ endpoint: endpoint.summary || endpoint.path,
260
+ purpose: inputs[:purpose],
261
+ generated_at: Time.now
262
+ }
263
+ }
264
+ end
265
+
266
+ # Export Model Context Protocol (MCP) for AI agents
267
+ endpoint(
268
+ GET('/mcp/export')
269
+ .summary('Export API for AI agent consumption')
270
+ .description('Generates MCP-compatible JSON for AI agents and development tools')
271
+ .tags('AI', 'MCP', 'Developer Tools')
272
+ .ok(T.hash({
273
+ "service" => T.hash({
274
+ "name" => T.string,
275
+ "version" => T.string,
276
+ "description" => T.string
277
+ }),
278
+ "endpoints" => T.array(T.hash({
279
+ "id" => T.string,
280
+ "method" => T.string,
281
+ "path" => T.string,
282
+ "summary" => T.string,
283
+ "input_schema" => T.hash({}),
284
+ "output_schema" => T.hash({})
285
+ })),
286
+ "generated_at" => T.datetime
287
+ }))
288
+ .build
289
+ ) do
290
+ exporter = RapiTapir::AI::MCP::Exporter.new(rapitapir_endpoints)
291
+ JSON.parse(exporter.export_json(pretty: true))
292
+ end
293
+
294
+ run! if __FILE__ == $0
295
+ end
296
+ ```
297
+
298
+ ### ๐Ÿ” OAuth2 + Auth0 Integration
299
+
300
+ ```ruby
301
+ class SecureAPI < SinatraRapiTapir
302
+ rapitapir do
303
+ info(title: 'Secure API with Auth0', version: '2.0.0')
304
+
305
+ # Configure Auth0 OAuth2
306
+ oauth2_auth0 :auth0,
307
+ domain: ENV['AUTH0_DOMAIN'],
308
+ audience: ENV['AUTH0_AUDIENCE'],
309
+ realm: 'API Access'
310
+
311
+ production_defaults! # Security headers, rate limiting, etc.
312
+ end
313
+
314
+ # Public endpoints
315
+ endpoint(
316
+ GET('/public/status')
317
+ .summary('Public API status')
318
+ .ok(T.hash({
319
+ "status" => T.string,
320
+ "version" => T.string,
321
+ "authenticated" => T.boolean
322
+ }))
323
+ .build
324
+ ) do
325
+ {
326
+ status: 'operational',
327
+ version: '2.0.0',
328
+ authenticated: authenticated?
329
+ }
330
+ end
331
+
332
+ # Protected endpoints with scope requirements
333
+ endpoint(
334
+ GET('/users/profile')
335
+ .summary('Get current user profile')
336
+ .description('Requires valid Auth0 token with read:profile scope')
337
+ .bearer_auth(scopes: ['read:profile'])
338
+ .tags('Users', 'Profile')
339
+ .ok(T.hash({
340
+ "user" => T.hash({
341
+ "id" => T.string,
342
+ "email" => T.string,
343
+ "name" => T.string,
344
+ "roles" => T.array(T.string),
345
+ "permissions" => T.array(T.string)
346
+ }),
347
+ "metadata" => T.hash({
348
+ "last_login" => T.datetime,
349
+ "login_count" => T.integer
350
+ })
351
+ }))
352
+ .error_response(401, T.hash({ "error" => T.string }), description: 'Unauthorized')
353
+ .error_response(403, T.hash({ "error" => T.string }), description: 'Insufficient permissions')
354
+ .build
355
+ ) do |inputs|
356
+ # Current user automatically available from Auth0 context
357
+ user_info = current_auth_context[:user_info]
358
+
359
+ {
360
+ user: {
361
+ id: user_info['sub'],
362
+ email: user_info['email'],
363
+ name: user_info['name'],
364
+ roles: user_info['roles'] || [],
365
+ permissions: current_auth_context[:permissions] || []
366
+ },
367
+ metadata: {
368
+ last_login: Time.parse(user_info['updated_at']),
369
+ login_count: user_info['logins_count'] || 0
370
+ }
371
+ }
372
+ end
373
+
374
+ # Admin-only endpoints
375
+ endpoint(
376
+ DELETE('/admin/users/:user_id')
377
+ .summary('Delete user (admin only)')
378
+ .path_param(:user_id, T.string, description: 'User ID to delete')
379
+ .bearer_auth(scopes: ['delete:users', 'admin'])
380
+ .tags('Admin', 'Users')
381
+ .ok(T.hash({ "message" => T.string, "deleted_user_id" => T.string }))
382
+ .error_response(401, T.hash({ "error" => T.string }))
383
+ .error_response(403, T.hash({ "error" => T.string }))
384
+ .error_response(404, T.hash({ "error" => T.string }))
385
+ .build
386
+ ) do |inputs|
387
+ # Verify admin scope
388
+ require_scope!('admin')
389
+
390
+ user_id = inputs[:user_id]
391
+ deleted_user = UserService.delete(user_id)
392
+
393
+ halt 404, { error: 'User not found' }.to_json unless deleted_user
394
+
395
+ {
396
+ message: 'User successfully deleted',
397
+ deleted_user_id: user_id
398
+ }
399
+ end
400
+
401
+ # Scope-based middleware protection
402
+ protect_with_oauth2 scopes: ['api:access'] do
403
+ # All endpoints in this block require the api:access scope
404
+
405
+ endpoint(
406
+ GET('/protected/data')
407
+ .summary('Get protected data')
408
+ .ok(T.array(T.hash({ "id" => T.integer, "data" => T.string })))
409
+ .build
410
+ ) { ProtectedData.all.map(&:to_h) }
411
+ end
412
+
413
+ run! if __FILE__ == $0
414
+ end
415
+ ```
416
+
417
+ ### ๐Ÿ“Š Production Observability (OpenTelemetry + Honeycomb)
418
+
419
+ ```ruby
420
+ class MonitoredAPI < SinatraRapiTapir
421
+ rapitapir do
422
+ info(title: 'Production API with Full Observability', version: '2.0.0')
423
+
424
+ # Configure comprehensive observability
425
+ enable_observability do |config|
426
+ # Health checks with custom checks
427
+ config.health_checks.enable(path: '/health')
428
+ config.health_checks.add_check('database') { DatabaseHealthCheck.new }
429
+ config.health_checks.add_check('redis') { RedisHealthCheck.new }
430
+ config.health_checks.add_check('external_api') { ExternalAPIHealthCheck.new }
431
+
432
+ # OpenTelemetry tracing
433
+ config.tracing.enable_opentelemetry(
434
+ service_name: 'book-api',
435
+ service_version: '2.0.0',
436
+ environment: ENV['RAILS_ENV'] || 'development',
437
+ exporters: [:otlp, :honeycomb]
438
+ )
439
+
440
+ # Prometheus metrics
441
+ config.metrics.enable_prometheus(
442
+ namespace: 'book_api',
443
+ default_labels: {
444
+ service: 'book-api',
445
+ version: '2.0.0',
446
+ environment: ENV['RAILS_ENV'] || 'development'
447
+ }
448
+ )
449
+
450
+ # Structured logging
451
+ config.logging.enable_structured(
452
+ level: ENV['LOG_LEVEL'] || 'info',
453
+ format: :json,
454
+ additional_fields: {
455
+ service: 'book-api',
456
+ version: '2.0.0'
457
+ }
458
+ )
459
+ end
460
+
461
+ production_defaults!
462
+ end
463
+
464
+ # Monitored endpoint with custom metrics and tracing
465
+ endpoint(
466
+ GET('/books/:id')
467
+ .path_param(:id, T.integer, description: 'Book ID')
468
+ .query(:include, T.optional(T.array(T.string)), description: 'Related data to include')
469
+ .summary('Get book with full observability')
470
+ .description('Demonstrates comprehensive monitoring, tracing, and metrics')
471
+ .tags('Books', 'Monitoring')
472
+ .ok(BOOK_SCHEMA)
473
+ .error_response(404, T.hash({ "error" => T.string, "book_id" => T.integer }))
474
+ .error_response(500, T.hash({ "error" => T.string, "trace_id" => T.string }))
475
+ .with_metrics('book_requests', labels: { operation: 'get_by_id' })
476
+ .with_tracing('fetch_book', tags: { book_operation: 'get' })
477
+ .build
478
+ ) do |inputs|
479
+ book_id = inputs[:id]
480
+ includes = inputs[:include] || []
481
+
482
+ # Custom span for database operation
483
+ OpenTelemetry.tracer.in_span('database.book.find', attributes: { 'book.id' => book_id }) do |span|
484
+ start_time = Time.now
485
+
486
+ begin
487
+ book = Book.find(book_id)
488
+
489
+ # Record custom metrics
490
+ Prometheus.increment('book_lookups_total', labels: { found: 'true' })
491
+ Prometheus.observe('book_lookup_duration_seconds', Time.now - start_time)
492
+
493
+ # Add trace attributes
494
+ span.set_attribute('book.title', book.title)
495
+ span.set_attribute('book.author', book.author)
496
+ span.set_attribute('includes.count', includes.length)
497
+
498
+ halt 404, { error: 'Book not found', book_id: book_id }.to_json unless book
499
+
500
+ # Handle includes with additional tracing
501
+ if includes.any?
502
+ OpenTelemetry.tracer.in_span('book.load_includes') do |include_span|
503
+ include_span.set_attribute('includes', includes.join(','))
504
+ book = book.with_includes(includes)
505
+ end
506
+ end
507
+
508
+ # Log structured data
509
+ logger.info('Book retrieved successfully', {
510
+ book_id: book_id,
511
+ includes: includes,
512
+ duration_ms: ((Time.now - start_time) * 1000).round(2),
513
+ trace_id: span.context.trace_id.unpack1('H*')
514
+ })
515
+
516
+ book.to_h
517
+
518
+ rescue StandardError => e
519
+ # Record error metrics
520
+ Prometheus.increment('book_lookup_errors_total', labels: { error_type: e.class.name })
521
+
522
+ # Add error to span
523
+ span.record_exception(e)
524
+ span.status = OpenTelemetry::Trace::Status.error('Book lookup failed')
525
+
526
+ # Log error with context
527
+ logger.error('Book lookup failed', {
528
+ book_id: book_id,
529
+ error: e.message,
530
+ error_class: e.class.name,
531
+ trace_id: span.context.trace_id.unpack1('H*')
532
+ })
533
+
534
+ halt 500, {
535
+ error: 'Internal server error',
536
+ trace_id: span.context.trace_id.unpack1('H*')
537
+ }.to_json
538
+ end
539
+ end
540
+ end
541
+
542
+ # Performance monitoring endpoint
543
+ endpoint(
544
+ GET('/monitoring/performance')
545
+ .summary('Get API performance metrics')
546
+ .description('Returns real-time performance and health metrics')
547
+ .tags('Monitoring', 'Performance')
548
+ .bearer_auth(scopes: ['monitoring:read'])
549
+ .ok(T.hash({
550
+ "metrics" => T.hash({
551
+ "request_rate" => T.float,
552
+ "error_rate" => T.float,
553
+ "average_response_time" => T.float,
554
+ "p95_response_time" => T.float
555
+ }),
556
+ "health" => T.hash({
557
+ "overall_status" => T.string,
558
+ "checks" => T.hash({})
559
+ }),
560
+ "trace_sample" => T.optional(T.hash({
561
+ "trace_id" => T.string,
562
+ "span_count" => T.integer,
563
+ "duration_ms" => T.float
564
+ }))
565
+ }))
566
+ .build
567
+ ) do
568
+ {
569
+ metrics: {
570
+ request_rate: MetricsCollector.request_rate_per_second,
571
+ error_rate: MetricsCollector.error_rate_percentage,
572
+ average_response_time: MetricsCollector.average_response_time_ms,
573
+ p95_response_time: MetricsCollector.p95_response_time_ms
574
+ },
575
+ health: {
576
+ overall_status: HealthChecker.overall_status,
577
+ checks: HealthChecker.detailed_status
578
+ },
579
+ trace_sample: TracingCollector.recent_trace_sample
580
+ }
581
+ end
582
+
583
+ run! if __FILE__ == $0
584
+ end
585
+ ```
586
+
587
+ ### ๐Ÿ› ๏ธ CLI Development Toolkit
588
+
589
+ RapiTapir includes a comprehensive CLI for all development tasks:
590
+
591
+ ```bash
592
+ # Generate and validate
593
+ rapitapir generate openapi --output api-spec.json
594
+ rapitapir generate client typescript --output client/api.ts
595
+ rapitapir generate docs markdown --output API.md
596
+ rapitapir validate endpoints --file my_api.rb
597
+
598
+ # AI-powered features
599
+ rapitapir llm generate --endpoint-id "get_books" --purpose validation
600
+ rapitapir llm export --format instructions --output ai-prompts/
601
+ rapitapir mcp export --output mcp-context.json
602
+
603
+ # Development server
604
+ rapitapir serve --port 3000 --docs-path /documentation
605
+ rapitapir docs --serve --port 8080
606
+
607
+ # Project scaffolding
608
+ rapitapir new my-api --template sinatra-ai
609
+ rapitapir generate scaffold books --with-auth --with-ai
610
+ ```
124
611
 
125
612
  ## ๐Ÿ—๏ธ Core Features
126
613
 
127
- ### Clean Base Class Syntax
614
+ ### โœจ SinatraRapiTapir Base Class
128
615
 
129
- Create APIs with the cleanest possible syntax:
616
+ The cleanest way to create APIs with zero boilerplate:
130
617
 
131
618
  ```ruby
132
619
  require 'rapitapir'
133
620
 
134
621
  class MyAPI < SinatraRapiTapir
135
622
  rapitapir do
136
- info(title: 'My API', version: '1.0.0')
137
- development_defaults! # Auto CORS, docs, health checks
623
+ info(title: 'My API', version: '2.0.0')
624
+ development_defaults! # Auto CORS, docs, health checks, metrics
138
625
  end
139
626
 
140
- # Enhanced HTTP verb DSL automatically available + T shortcut for types
627
+ # Enhanced HTTP verb DSL + T shortcut automatically available
141
628
  endpoint(
142
- GET('/books')
143
- .summary('List all books')
144
- .ok(T.array(BOOK_SCHEMA))
145
- .error_response(500, T.hash({ "error" => T.string }))
629
+ GET('/items')
630
+ .summary('List all items')
631
+ .query(:filter, T.optional(T.string), description: 'Filter criteria')
632
+ .ok(T.array(T.hash({ "id" => T.integer, "name" => T.string })))
146
633
  .build
147
- ) { Book.all }
634
+ ) { |inputs| Item.filtered(inputs[:filter]).map(&:to_h) }
148
635
  end
149
636
  ```
150
637
 
151
- ### Type-Safe API Design
638
+ ### ๐Ÿ”’ Type-Safe API Design
152
639
 
153
- Define your data schemas once and use them everywhere:
640
+ Define schemas once, use everywhere with runtime validation:
154
641
 
155
642
  ```ruby
156
- # T shortcut is automatically available - no setup needed!
643
+ # T shortcut available globally - no imports needed!
157
644
  USER_SCHEMA = T.hash({
158
645
  "id" => T.integer,
159
646
  "name" => T.string(min_length: 1, max_length: 100),
160
647
  "email" => T.email,
161
- "age" => T.optional(T.integer(min: 0, max: 150)),
162
- "profile" => T.optional(T.hash({
163
- "bio" => T.string(max_length: 500),
164
- "avatar_url" => T.string(format: :url)
165
- }))
648
+ "age" => T.optional(T.integer(minimum: 0, maximum: 150)),
649
+ "preferences" => T.optional(T.hash({
650
+ "theme" => T.string(enum: %w[light dark auto]),
651
+ "notifications" => T.boolean,
652
+ "languages" => T.array(T.string)
653
+ })),
654
+ "metadata" => T.optional(T.hash({})) # Free-form metadata
655
+ })
656
+
657
+ # Auto-derive schemas from existing data
658
+ INFERRED_SCHEMA = T.from_hash({
659
+ id: 1,
660
+ name: "John Doe",
661
+ active: true,
662
+ tags: ["admin", "power-user"]
166
663
  })
167
664
  ```
168
665
 
169
- ### Fluent Endpoint Definition
666
+ ### ๐Ÿš€ Enhanced HTTP Verb DSL
170
667
 
171
- Create endpoints with a clean, readable DSL:
668
+ Fluent, chainable endpoint definitions:
172
669
 
173
670
  ```ruby
174
- # Using the enhanced HTTP verb DSL with T shortcut
671
+ # All HTTP verbs available with full type safety
175
672
  endpoint(
176
- GET('/users/:id')
177
- .summary('Get user by ID')
178
- .path_param(:id, T.integer(minimum: 1))
179
- .query(:include, T.optional(T.array(T.string)), description: 'Related data to include')
180
- .ok(USER_SCHEMA)
181
- .error_response(404, T.hash({ "error" => T.string }), description: 'User not found')
182
- .error_response(422, T.hash({
673
+ POST('/users')
674
+ .summary('Create a new user')
675
+ .description('Creates a user with validation and returns the created resource')
676
+ .tags('Users', 'CRUD')
677
+ .body(USER_SCHEMA, description: 'User data to create')
678
+ .header('X-Request-ID', T.optional(T.string), description: 'Request tracking ID')
679
+ .ok(USER_SCHEMA, description: 'Successfully created user')
680
+ .error_response(400, T.hash({
183
681
  "error" => T.string,
184
- "details" => T.array(T.hash({
682
+ "validation_errors" => T.array(T.hash({
185
683
  "field" => T.string,
186
- "message" => T.string
684
+ "message" => T.string,
685
+ "code" => T.string
187
686
  }))
188
- }))
687
+ }), description: 'Validation failed')
688
+ .error_response(409, T.hash({ "error" => T.string }), description: 'User already exists')
189
689
  .build
190
690
  ) do |inputs|
191
- user = User.find(inputs[:id])
192
- halt 404, { error: 'User not found' }.to_json unless user
193
-
194
- # Handle optional includes
195
- if inputs[:include]&.include?('profile')
196
- user = user.with_profile
691
+ begin
692
+ user = UserService.create(inputs[:body])
693
+ status 201
694
+ user.to_h
695
+ rescue ValidationError => e
696
+ halt 400, {
697
+ error: 'Validation failed',
698
+ validation_errors: e.details
699
+ }.to_json
700
+ rescue ConflictError => e
701
+ halt 409, { error: e.message }.to_json
197
702
  end
198
-
199
- user.to_h
200
703
  end
201
704
  ```
202
705
 
203
- ### RESTful Resource Builder
706
+ ### ๐Ÿญ RESTful Resource Builder
204
707
 
205
- Build complete CRUD APIs with minimal code:
708
+ Complete CRUD APIs with minimal code:
206
709
 
207
710
  ```ruby
208
- # Enhanced resource builder with custom validations and relationships
209
711
  api_resource '/users', schema: USER_SCHEMA do
210
- crud do
211
- index do
212
- # Automatic pagination and filtering
712
+ # Configure resource-level settings
713
+ configure do
714
+ pagination default_limit: 25, max_limit: 100
715
+ filtering allow: [:name, :email, :active]
716
+ sorting allow: [:name, :created_at, :updated_at]
717
+ end
718
+
719
+ crud except: [:destroy] do # Exclude dangerous operations
720
+ index do |inputs|
213
721
  users = User.all
214
- users = users.where(active: true) if params[:active] == 'true'
215
- users.limit(params[:limit] || 50)
722
+ users = users.where(active: true) if inputs[:filter_active]
723
+ users = users.search(inputs[:search]) if inputs[:search]
724
+
725
+ paginated_response(
726
+ data: users.map(&:to_h),
727
+ page: inputs[:page] || 1,
728
+ per_page: inputs[:per_page] || 25,
729
+ total: users.count
730
+ )
216
731
  end
217
732
 
218
- show { |inputs| User.find(inputs[:id]) }
733
+ show { |inputs| User.find(inputs[:id])&.to_h || halt(404) }
219
734
 
220
735
  create do |inputs|
221
- user = User.create(inputs[:body])
736
+ user = User.create!(inputs[:body])
222
737
  status 201
738
+ location "/users/#{user.id}"
223
739
  user.to_h
224
740
  end
225
741
 
226
- update { |inputs| User.update(inputs[:id], inputs[:body]) }
227
- destroy { |inputs| User.delete(inputs[:id]); status 204 }
742
+ update do |inputs|
743
+ user = User.find(inputs[:id]) || halt(404)
744
+ user.update!(inputs[:body])
745
+ user.to_h
746
+ end
228
747
  end
229
748
 
230
- # Add custom endpoints with full type safety
231
- custom :get, 'active' do
232
- User.where(active: true).map(&:to_h)
749
+ # Custom endpoints with full inheritance of resource configuration
750
+ custom :post, ':id/avatar' do |inputs|
751
+ user = User.find(inputs[:id]) || halt(404)
752
+ avatar = user.update_avatar(inputs[:body][:avatar_data])
753
+ { avatar_url: avatar.url, updated_at: avatar.updated_at }
233
754
  end
234
755
 
235
- custom :post, ':id/avatar' do |inputs|
236
- user = User.find(inputs[:id])
237
- user.update_avatar(inputs[:body][:avatar_data])
238
- { success: true }
756
+ custom :get, 'search/advanced' do |inputs|
757
+ # Advanced search with multiple criteria
758
+ results = UserSearchService.advanced_search(inputs)
759
+ { users: results.map(&:to_h), search_metadata: results.metadata }
239
760
  end
240
761
  end
241
762
  ```
242
763
 
243
- ### Automatic OpenAPI Documentation
764
+ ### ๐Ÿ“– Automatic Documentation
244
765
 
245
- Your API documentation is always up-to-date because it's generated from your actual code:
766
+ Your API documentation is always up-to-date:
246
767
 
247
- - **Interactive Swagger UI** with try-it-out functionality
248
- - **Complete OpenAPI 3.0 specification** with schemas, examples, and security
249
- - **TypeScript client generation** for frontend teams
250
- - **Markdown documentation** for wikis and READMEs
768
+ - **Interactive Swagger UI**: Try endpoints directly from the browser
769
+ - **Complete OpenAPI 3.0**: Full specification with schemas, examples, security
770
+ - **TypeScript clients**: Auto-generated for frontend teams
771
+ - **Markdown docs**: Perfect for wikis and README files
772
+ - **CLI generation**: `rapitapir generate docs --format html`
251
773
 
252
774
  ## ๐Ÿ”ง Framework Integration
253
775
 
254
776
  ### Sinatra (Recommended)
255
777
 
256
- **Option 1: Clean Base Class (Recommended)**
778
+ **Option 1: SinatraRapiTapir Base Class**
257
779
  ```ruby
258
780
  require 'rapitapir'
259
781
 
260
782
  class MyAPI < SinatraRapiTapir
261
783
  rapitapir do
262
- info(title: 'My API', version: '1.0.0')
784
+ info(title: 'My API', version: '2.0.0')
263
785
  development_defaults!
264
786
  end
265
- # Enhanced HTTP verb DSL automatically available
787
+ # Enhanced HTTP verb DSL + T shortcut automatically available
266
788
  end
267
789
  ```
268
790
 
269
- **Option 2: Manual Extension Registration**
791
+ **Option 2: Manual Extension**
270
792
  ```ruby
271
793
  require 'rapitapir/sinatra/extension'
272
794
 
273
795
  class MyAPI < Sinatra::Base
274
796
  register RapiTapir::Sinatra::Extension
275
- # Use the full DSL...
797
+ # Use full DSL manually...
798
+ end
799
+ ```
800
+
801
+ ### Rails Integration
802
+
803
+ ```ruby
804
+ # app/controllers/api/base_controller.rb
805
+ class Api::BaseController < ApplicationController
806
+ include RapiTapir::Server::Rails::ControllerBase
807
+
808
+ rapitapir do
809
+ info(title: 'Rails API', version: '1.0.0')
810
+ bearer_auth :jwt
811
+ end
812
+ end
813
+
814
+ # app/controllers/api/users_controller.rb
815
+ class Api::UsersController < Api::BaseController
816
+ endpoint(
817
+ GET('/users')
818
+ .summary('List users')
819
+ .ok(T.array(USER_SCHEMA))
820
+ .build
821
+ ) { User.all.map(&:to_h) }
276
822
  end
277
823
  ```
278
824
 
@@ -282,204 +828,742 @@ end
282
828
  require 'rapitapir/server/rack_adapter'
283
829
 
284
830
  class MyRackApp
285
- def call(env)
286
- # Manual integration with Rack
831
+ include RapiTapir::Server::RackAdapter
832
+
833
+ def initialize
834
+ register_endpoints
835
+ end
836
+
837
+ private
838
+
839
+ def register_endpoints
840
+ endpoint(GET('/status').ok(T.hash({ "status" => T.string })).build) do
841
+ { status: 'ok' }
842
+ end
843
+ end
844
+ end
845
+ ```
846
+
847
+ ## โ˜๏ธ Serverless Deployment
848
+
849
+ RapiTapir APIs can be deployed as serverless functions across all major cloud providers with zero configuration changes. The same SinatraRapiTapir code runs seamlessly on AWS Lambda, Google Cloud Functions, Azure Functions, and Vercel.
850
+
851
+ ### ๐Ÿš€ AWS Lambda
852
+
853
+ ```ruby
854
+ require 'rapitapir'
855
+
856
+ class ServerlessAPI < SinatraRapiTapir
857
+ rapitapir do
858
+ info(title: 'Serverless API', version: '1.0.0')
859
+ development_defaults!
287
860
  end
861
+
862
+ endpoint(GET('/hello').query(:name, T.string).ok(T.hash({"message" => T.string})).build) do |inputs|
863
+ { message: "Hello from Lambda, #{inputs[:name]}!" }
864
+ end
865
+ end
866
+
867
+ # Lambda handler
868
+ def lambda_handler(event:, context:)
869
+ rack_env = build_rack_env_from_api_gateway(event, context)
870
+ app = ServerlessAPI.new
871
+ status, headers, body = app.call(rack_env)
872
+ build_api_gateway_response(status, headers, body)
873
+ end
874
+ ```
875
+
876
+ **Deploy with AWS SAM**:
877
+ ```bash
878
+ sam build && sam deploy
879
+ ```
880
+
881
+ ### โ˜๏ธ Google Cloud Functions
882
+
883
+ ```ruby
884
+ require 'functions_framework'
885
+
886
+ FunctionsFramework.http('my_api') do |request|
887
+ rack_env = build_rack_env_from_cloud_functions(request)
888
+ app = ServerlessAPI.new
889
+ app.call(rack_env)
288
890
  end
289
891
  ```
290
892
 
291
- ### Rails Support
893
+ **Deploy**:
894
+ ```bash
895
+ gcloud functions deploy my-api --runtime ruby32 --trigger-http
896
+ ```
897
+
898
+ ### ๐ŸŒ Vercel Edge Functions
292
899
 
293
900
  ```ruby
294
- # In your Rails controller
295
- include RapiTapir::Rails::Controller
901
+ def handler(request:, response:)
902
+ rack_env = build_rack_env_from_vercel(request)
903
+ app = ServerlessAPI.new
904
+ status, headers, body = app.call(rack_env)
905
+
906
+ response.status = status
907
+ headers.each { |k, v| response[k] = v }
908
+ response.write(body.join)
909
+ end
910
+ ```
911
+
912
+ **Deploy**:
913
+ ```bash
914
+ vercel --prod
296
915
  ```
297
916
 
917
+ ### Key Benefits
918
+
919
+ - **๐Ÿš€ Zero Cold Start Impact**: Optimized for fast function startup
920
+ - **๐Ÿ’ฐ Cost Effective**: Pay only for actual requests
921
+ - **๐ŸŒ Global Scale**: Deploy to edge locations worldwide
922
+ - **๐Ÿ”’ Built-in Security**: Leverage cloud provider security
923
+ - **๐Ÿ“Š Native Monitoring**: Integrate with cloud monitoring
924
+
925
+ ### Complete Examples
926
+
927
+ See [examples/serverless/](examples/serverless/) for production-ready examples including:
928
+
929
+ - **AWS Lambda + API Gateway**: Full SAM template with DynamoDB
930
+ - **Google Cloud Functions**: With Firestore integration
931
+ - **Azure Functions**: With Cosmos DB and Service Bus
932
+ - **Vercel Edge**: With global edge caching
933
+ - **Multi-cloud deployment**: GitHub Actions workflows
934
+
298
935
  ## ๐Ÿ›ก๏ธ Production Features
299
936
 
300
- ### Authentication & Authorization
937
+ ### ๐Ÿ” Authentication & Authorization
301
938
 
302
939
  ```ruby
303
- # Bearer token authentication with enhanced syntax
304
940
  class SecureAPI < SinatraRapiTapir
305
941
  rapitapir do
306
- info(title: 'Secure API', version: '1.0.0')
942
+ info(title: 'Secure API', version: '2.0.0')
943
+
944
+ # Multiple auth schemes supported
307
945
  bearer_auth :api_key, realm: 'API'
946
+ oauth2_auth0 :auth0, domain: ENV['AUTH0_DOMAIN'], audience: ENV['AUTH0_AUDIENCE']
947
+ basic_auth :admin, realm: 'Admin Panel'
948
+
949
+ production_defaults! # Security headers, rate limiting, HTTPS enforcement
950
+ end
951
+
952
+ # Scope-based protection
953
+ protect_with_oauth2 scopes: ['api:read'] do
954
+ endpoint(GET('/protected/data').ok(T.array(T.hash({}))).build) { ProtectedData.all }
955
+ end
956
+
957
+ # Fine-grained permissions
958
+ endpoint(
959
+ DELETE('/admin/users/:id')
960
+ .path_param(:id, T.integer)
961
+ .bearer_auth(scopes: ['admin', 'users:delete'])
962
+ .ok(T.hash({ "message" => T.string }))
963
+ .build
964
+ ) do |inputs|
965
+ require_scope!('admin') # Additional runtime check
966
+ UserService.delete(inputs[:id])
967
+ { message: 'User deleted successfully' }
968
+ end
969
+ end
970
+ ```
971
+
972
+ ### ๐Ÿ“Š Observability & Monitoring
973
+
974
+ ```ruby
975
+ class MonitoredAPI < SinatraRapiTapir
976
+ rapitapir do
977
+ info(title: 'Production API', version: '2.0.0')
978
+
979
+ enable_observability do |config|
980
+ # Health checks with custom probes
981
+ config.health_checks.enable(path: '/health')
982
+ config.health_checks.add_check('database') { Database.healthy? }
983
+ config.health_checks.add_check('redis') { Redis.current.ping == 'PONG' }
984
+
985
+ # OpenTelemetry integration
986
+ config.tracing.enable_opentelemetry(
987
+ service_name: 'my-api',
988
+ exporters: [:honeycomb, :jaeger],
989
+ sample_rate: 0.1
990
+ )
991
+
992
+ # Prometheus metrics
993
+ config.metrics.enable_prometheus(
994
+ namespace: 'my_api',
995
+ path: '/metrics'
996
+ )
997
+
998
+ # Structured logging
999
+ config.logging.enable_structured(format: :json)
1000
+ end
1001
+ end
1002
+
1003
+ # Endpoints with observability
1004
+ endpoint(
1005
+ GET('/monitored-endpoint')
1006
+ .with_metrics('endpoint_requests', labels: { operation: 'get' })
1007
+ .with_tracing('fetch_data')
1008
+ .ok(T.hash({}))
1009
+ .build
1010
+ ) do
1011
+ # Custom spans and metrics automatically collected
1012
+ { data: 'response' }
1013
+ end
1014
+ end
1015
+ ```
1016
+
1017
+ ### ๐Ÿ”’ Security Middleware
1018
+
1019
+ Built-in security features for production deployments:
1020
+
1021
+ ```ruby
1022
+ # Automatic security middleware
1023
+ use RapiTapir::Server::Middleware::SecurityHeaders
1024
+ use RapiTapir::Server::Middleware::RateLimit, requests_per_minute: 100
1025
+ use RapiTapir::Server::Middleware::CORS, origins: ['https://myapp.com']
1026
+ use RapiTapir::Server::Middleware::RequestValidation
1027
+ ```
1028
+
1029
+ ## ๐Ÿค– AI Integration Features
1030
+
1031
+ ### LLM Instruction Generation
1032
+
1033
+ Generate context-aware instructions for any endpoint:
1034
+
1035
+ ```ruby
1036
+ # Generate instructions for different AI purposes
1037
+ generator = RapiTapir::AI::LLMInstruction::Generator.new
1038
+
1039
+ # Validation instructions
1040
+ validation_prompt = generator.generate_instructions(
1041
+ endpoint: my_endpoint,
1042
+ purpose: :validation
1043
+ )
1044
+
1045
+ # Documentation instructions
1046
+ docs_prompt = generator.generate_instructions(
1047
+ endpoint: my_endpoint,
1048
+ purpose: :documentation
1049
+ )
1050
+
1051
+ # Test generation instructions
1052
+ test_prompt = generator.generate_instructions(
1053
+ endpoint: my_endpoint,
1054
+ purpose: :testing
1055
+ )
1056
+ ```
1057
+
1058
+ ### RAG (Retrieval-Augmented Generation)
1059
+
1060
+ Enable semantic search and context-aware responses:
1061
+
1062
+ ```ruby
1063
+ endpoint(
1064
+ GET('/books/semantic-search')
1065
+ .query(:query, T.string)
1066
+ .enable_rag(
1067
+ retrieval_backend: :memory, # or :elasticsearch, :postgresql
1068
+ llm_provider: :openai,
1069
+ context_window: 4000
1070
+ )
1071
+ .ok(T.hash({
1072
+ "results" => T.array(BOOK_SCHEMA),
1073
+ "context" => T.string,
1074
+ "confidence" => T.float
1075
+ }))
1076
+ .build
1077
+ ) do |inputs|
1078
+ # RAG context automatically injected
1079
+ rag_enhanced_search(inputs[:query], context: rag_context)
1080
+ end
1081
+ ```
1082
+
1083
+ ### Model Context Protocol (MCP)
1084
+
1085
+ Export your API for AI agent consumption:
1086
+
1087
+ ```ruby
1088
+ # Export MCP-compatible JSON
1089
+ exporter = RapiTapir::AI::MCP::Exporter.new(rapitapir_endpoints)
1090
+ mcp_json = exporter.export_json(pretty: true)
1091
+
1092
+ # CLI export
1093
+ # rapitapir mcp export --output api-context.json
1094
+ ```
1095
+
1096
+ ## ๐ŸŽจ Complete Examples
1097
+
1098
+ ### ๐Ÿ“š Library Management System
1099
+
1100
+ A comprehensive example showcasing all features:
1101
+
1102
+ ```ruby
1103
+ require 'rapitapir'
1104
+
1105
+ class LibraryAPI < SinatraRapiTapir
1106
+ rapitapir do
1107
+ info(
1108
+ title: 'Library Management System',
1109
+ description: 'Complete library API with AI, auth, and observability',
1110
+ version: '2.0.0',
1111
+ contact: { name: 'API Team', email: 'api@library.com' }
1112
+ )
1113
+
1114
+ # Auth configuration
1115
+ oauth2_auth0 :auth0,
1116
+ domain: ENV['AUTH0_DOMAIN'],
1117
+ audience: ENV['AUTH0_AUDIENCE']
1118
+
1119
+ # Observability
1120
+ enable_observability do |config|
1121
+ config.health_checks.enable
1122
+ config.tracing.enable_opentelemetry(service_name: 'library-api')
1123
+ config.metrics.enable_prometheus
1124
+ end
1125
+
308
1126
  production_defaults!
309
1127
  end
310
1128
 
311
- # Protected endpoint with scope-based authorization
1129
+ # Schemas
1130
+ BOOK_SCHEMA = T.hash({
1131
+ "id" => T.integer,
1132
+ "isbn" => T.string(pattern: /^\d{13}$/),
1133
+ "title" => T.string(min_length: 1, max_length: 500),
1134
+ "authors" => T.array(T.string),
1135
+ "published_date" => T.date,
1136
+ "genres" => T.array(T.string),
1137
+ "available_copies" => T.integer(minimum: 0),
1138
+ "total_copies" => T.integer(minimum: 1),
1139
+ "metadata" => T.optional(T.hash({}))
1140
+ })
1141
+
1142
+ MEMBER_SCHEMA = T.hash({
1143
+ "id" => T.integer,
1144
+ "email" => T.email,
1145
+ "name" => T.string(min_length: 1),
1146
+ "member_since" => T.date,
1147
+ "active" => T.boolean,
1148
+ "borrowed_books" => T.array(T.integer)
1149
+ })
1150
+
1151
+ # Public endpoints
312
1152
  endpoint(
313
- GET('/admin/users')
314
- .summary('List all users (admin only)')
315
- .bearer_auth(scopes: ['admin'])
316
- .query(:page, T.optional(T.integer(minimum: 1)), description: 'Page number')
317
- .query(:per_page, T.optional(T.integer(minimum: 1, maximum: 100)), description: 'Items per page')
1153
+ GET('/books/search')
1154
+ .query(:q, T.string(min_length: 1), description: 'Search query')
1155
+ .query(:ai_enhanced, T.optional(T.boolean), description: 'Use AI semantic search')
1156
+ .summary('Search books with optional AI enhancement')
1157
+ .tags('Books', 'Search')
318
1158
  .ok(T.hash({
319
- "users" => T.array(USER_SCHEMA),
320
- "pagination" => T.hash({
321
- "page" => T.integer,
322
- "per_page" => T.integer,
323
- "total" => T.integer,
324
- "pages" => T.integer
325
- })
1159
+ "books" => T.array(BOOK_SCHEMA),
1160
+ "total" => T.integer,
1161
+ "ai_enhanced" => T.boolean
326
1162
  }))
327
- .error_response(401, T.hash({ "error" => T.string }), description: 'Unauthorized')
328
- .error_response(403, T.hash({ "error" => T.string }), description: 'Insufficient permissions')
1163
+ .enable_rag
1164
+ .enable_mcp
329
1165
  .build
330
1166
  ) do |inputs|
331
- require_scope!('admin')
332
-
333
- page = inputs[:page] || 1
334
- per_page = inputs[:per_page] || 20
335
-
336
- users = User.paginate(page: page, per_page: per_page)
1167
+ if inputs[:ai_enhanced]
1168
+ results = AIBookSearch.semantic_search(inputs[:q], context: rag_context)
1169
+ else
1170
+ results = Book.search(inputs[:q])
1171
+ end
337
1172
 
338
1173
  {
339
- users: users.map(&:to_h),
340
- pagination: {
341
- page: page,
342
- per_page: per_page,
343
- total: users.total_count,
344
- pages: users.total_pages
345
- }
1174
+ books: results.map(&:to_h),
1175
+ total: results.count,
1176
+ ai_enhanced: !!inputs[:ai_enhanced]
346
1177
  }
347
1178
  end
1179
+
1180
+ # Protected member endpoints
1181
+ protect_with_oauth2 scopes: ['library:read'] do
1182
+ api_resource '/books', schema: BOOK_SCHEMA do
1183
+ crud only: [:index, :show] do
1184
+ index { Book.available.map(&:to_h) }
1185
+ show { |inputs| Book.find(inputs[:id])&.to_h || halt(404) }
1186
+ end
1187
+
1188
+ custom :post, ':id/reserve' do |inputs|
1189
+ book = Book.find(inputs[:id]) || halt(404)
1190
+ member = current_member
1191
+
1192
+ reservation = ReservationService.create(book: book, member: member)
1193
+ { reservation_id: reservation.id, expires_at: reservation.expires_at }
1194
+ end
1195
+ end
1196
+
1197
+ endpoint(
1198
+ GET('/members/me/profile')
1199
+ .summary('Get current member profile')
1200
+ .bearer_auth(scopes: ['profile:read'])
1201
+ .ok(MEMBER_SCHEMA)
1202
+ .build
1203
+ ) { current_member.to_h }
1204
+ end
1205
+
1206
+ # Admin endpoints
1207
+ protect_with_oauth2 scopes: ['library:admin'] do
1208
+ api_resource '/admin/books', schema: BOOK_SCHEMA do
1209
+ crud do
1210
+ index { Book.all.map(&:to_h) }
1211
+ show { |inputs| Book.find(inputs[:id])&.to_h || halt(404) }
1212
+ create { |inputs| Book.create!(inputs[:body]).to_h }
1213
+ update { |inputs| Book.update!(inputs[:id], inputs[:body]).to_h }
1214
+ destroy { |inputs| Book.destroy(inputs[:id]); status 204 }
1215
+ end
1216
+ end
1217
+
1218
+ # AI-powered book recommendations
1219
+ endpoint(
1220
+ POST('/admin/ai/recommend-acquisitions')
1221
+ .body(T.hash({
1222
+ "budget" => T.float(minimum: 0),
1223
+ "categories" => T.optional(T.array(T.string)),
1224
+ "member_preferences" => T.optional(T.boolean)
1225
+ }))
1226
+ .summary('Get AI-powered book acquisition recommendations')
1227
+ .tags('Admin', 'AI', 'Recommendations')
1228
+ .ok(T.hash({
1229
+ "recommendations" => T.array(T.hash({
1230
+ "title" => T.string,
1231
+ "author" => T.string,
1232
+ "estimated_cost" => T.float,
1233
+ "demand_score" => T.float,
1234
+ "reasoning" => T.string
1235
+ })),
1236
+ "total_estimated_cost" => T.float,
1237
+ "confidence" => T.float
1238
+ }))
1239
+ .enable_llm_instructions(purpose: :completion)
1240
+ .build
1241
+ ) do |inputs|
1242
+ recommendations = AIAcquisitionService.recommend(
1243
+ budget: inputs[:budget],
1244
+ categories: inputs[:categories],
1245
+ consider_member_preferences: inputs[:member_preferences],
1246
+ context: library_context
1247
+ )
1248
+
1249
+ {
1250
+ recommendations: recommendations[:items],
1251
+ total_estimated_cost: recommendations[:total_cost],
1252
+ confidence: recommendations[:confidence_score]
1253
+ }
1254
+ end
1255
+ end
1256
+
1257
+ run! if __FILE__ == $0
348
1258
  end
349
1259
  ```
350
1260
 
351
- ### Observability
1261
+ ### ๐Ÿฅ Healthcare API Example
352
1262
 
353
1263
  ```ruby
354
- class MonitoredAPI < SinatraRapiTapir
1264
+ class HealthcareAPI < SinatraRapiTapir
355
1265
  rapitapir do
356
- info(title: 'Monitored API', version: '1.0.0')
357
- enable_health_checks path: '/health'
358
- enable_metrics
1266
+ info(
1267
+ title: 'Healthcare Management API',
1268
+ description: 'HIPAA-compliant healthcare API with AI diagnostics',
1269
+ version: '2.0.0'
1270
+ )
1271
+
1272
+ # Strict security for healthcare
1273
+ bearer_auth :jwt, realm: 'Healthcare'
1274
+
1275
+ enable_observability do |config|
1276
+ config.health_checks.enable
1277
+ config.tracing.enable_opentelemetry(
1278
+ service_name: 'healthcare-api',
1279
+ compliance_mode: :hipaa
1280
+ )
1281
+ config.logging.enable_structured(
1282
+ format: :json,
1283
+ exclude_fields: [:ssn, :medical_record_number] # PII protection
1284
+ )
1285
+ end
1286
+
359
1287
  production_defaults!
360
1288
  end
361
1289
 
362
- # Endpoint with metrics and tracing
1290
+ PATIENT_SCHEMA = T.hash({
1291
+ "id" => T.string, # UUID for privacy
1292
+ "name" => T.hash({
1293
+ "first" => T.string,
1294
+ "last" => T.string
1295
+ }),
1296
+ "date_of_birth" => T.date,
1297
+ "medical_record_number" => T.string,
1298
+ "insurance" => T.optional(T.hash({}))
1299
+ })
1300
+
1301
+ # AI-powered diagnostic assistance
363
1302
  endpoint(
364
- GET('/api/data')
365
- .summary('Get data with monitoring')
366
- .with_metrics('api_data_requests')
367
- .with_tracing('fetch_api_data')
368
- .query(:filter, T.optional(T.string), description: 'Data filter')
1303
+ POST('/diagnostics/analyze')
1304
+ .body(T.hash({
1305
+ "patient_id" => T.string,
1306
+ "symptoms" => T.array(T.string),
1307
+ "vital_signs" => T.hash({
1308
+ "temperature" => T.optional(T.float),
1309
+ "blood_pressure" => T.optional(T.string),
1310
+ "heart_rate" => T.optional(T.integer)
1311
+ }),
1312
+ "medical_history" => T.optional(T.array(T.string))
1313
+ }))
1314
+ .summary('AI-assisted diagnostic analysis')
1315
+ .bearer_auth(scopes: ['diagnostics:read', 'ai:analyze'])
1316
+ .tags('Diagnostics', 'AI')
369
1317
  .ok(T.hash({
370
- "data" => T.array(T.hash({
371
- "id" => T.integer,
372
- "value" => T.string,
373
- "timestamp" => T.datetime
374
- })),
375
- "metadata" => T.hash({
376
- "total" => T.integer,
377
- "filtered" => T.boolean
378
- })
1318
+ "analysis" => T.hash({
1319
+ "suggested_conditions" => T.array(T.hash({
1320
+ "condition" => T.string,
1321
+ "confidence" => T.float,
1322
+ "reasoning" => T.string
1323
+ })),
1324
+ "recommended_tests" => T.array(T.string),
1325
+ "urgency_level" => T.string(enum: %w[low medium high critical])
1326
+ }),
1327
+ "disclaimer" => T.string,
1328
+ "generated_at" => T.datetime
379
1329
  }))
1330
+ .enable_llm_instructions(purpose: :analysis)
380
1331
  .build
381
1332
  ) do |inputs|
382
- # Your endpoint code with automatic metrics collection
383
- data = DataService.fetch(filter: inputs[:filter])
1333
+ # Verify provider permissions
1334
+ require_scope!('diagnostics:read')
1335
+
1336
+ # AI diagnostic analysis with medical context
1337
+ analysis = MedicalAI.analyze_symptoms(
1338
+ patient_id: inputs[:patient_id],
1339
+ symptoms: inputs[:symptoms],
1340
+ vital_signs: inputs[:vital_signs],
1341
+ medical_history: inputs[:medical_history],
1342
+ provider_context: current_provider_context
1343
+ )
384
1344
 
385
1345
  {
386
- data: data.map(&:to_h),
387
- metadata: {
388
- total: data.count,
389
- filtered: inputs[:filter].present?
390
- }
1346
+ analysis: analysis,
1347
+ disclaimer: "This analysis is for informational purposes only and should not replace professional medical judgment.",
1348
+ generated_at: Time.now
391
1349
  }
392
1350
  end
1351
+
1352
+ run! if __FILE__ == $0
393
1353
  end
394
1354
  ```
395
1355
 
396
- ### Security Middleware
1356
+ ## ๐Ÿ“š Documentation
397
1357
 
398
- ```ruby
399
- # Built-in security features
400
- use RapiTapir::Server::Middleware::CORS
401
- use RapiTapir::Server::Middleware::RateLimit, requests_per_minute: 100
402
- use RapiTapir::Server::Middleware::SecurityHeaders
1358
+ ### Core Guides
1359
+
1360
+ - **[Getting Started Guide](examples/working_simple_example.rb)** - Your first RapiTapir API in 5 minutes
1361
+ - **[SinatraRapiTapir Base Class](docs/sinatra_rapitapir.md)** - Zero-boilerplate API creation
1362
+ - **[Enhanced HTTP DSL](docs/endpoint-definition.md)** - Complete endpoint definition guide
1363
+ - **[Type System & T Shortcut](docs/type_shortcuts.md)** - All available types and validations
1364
+ - **[Resource Builder](docs/RAILS_INTEGRATION_IMPLEMENTATION.md)** - RESTful CRUD with minimal code
1365
+
1366
+ ### Advanced Features
1367
+
1368
+ - **[AI Integration](docs/auto-derivation.md)** - LLM instructions, RAG pipelines, MCP export
1369
+ - **[Authentication & Security](examples/authentication_example.rb)** - OAuth2, JWT, scopes, and Auth0
1370
+ - **[Observability](docs/observability.md)** - OpenTelemetry, health checks, metrics
1371
+ - **[CLI Toolkit](docs/blueprint.md)** - Complete command-line development workflow
1372
+
1373
+ ### Framework Integration
1374
+
1375
+ - **[Sinatra Extension](docs/SINATRA_EXTENSION.md)** - Detailed Sinatra integration guide
1376
+ - **[Rails Integration](docs/RAILS_INTEGRATION_IMPLEMENTATION.md)** - Controller-based Rails APIs
1377
+ - **[Rack Applications](docs/implementation-status.md)** - Direct Rack integration
1378
+
1379
+ ### Examples & Templates
1380
+
1381
+ Explore our comprehensive examples directory:
1382
+
1383
+ - **[Hello World](examples/hello_world.rb)** - 30-second minimal example
1384
+ - **[Enterprise API](examples/enterprise_rapitapir_api.rb)** - Production-ready with all features
1385
+ - **[Serverless Deployment](examples/serverless/)** - AWS Lambda, Google Cloud Functions, Azure Functions, Vercel
1386
+ - **[OAuth2 + Auth0](examples/oauth2/)** - Complete authentication examples
1387
+ - **[AI-Powered APIs](examples/auto_derivation_ruby_friendly.rb)** - LLM and RAG integration
1388
+ - **[Observability Setup](examples/observability/)** - Monitoring and health checks
1389
+ - **[CLI Examples](examples/cli/)** - Command-line toolkit usage
1390
+
1391
+ ## ๐Ÿ› ๏ธ CLI Development Toolkit
1392
+
1393
+ RapiTapir includes a powerful CLI for streamlined development:
1394
+
1395
+ ### Code Generation
1396
+ ```bash
1397
+ # Generate OpenAPI specifications
1398
+ rapitapir generate openapi --output api-spec.json --format json
1399
+ rapitapir generate openapi --output api-spec.yaml --format yaml
1400
+
1401
+ # Generate TypeScript clients
1402
+ rapitapir generate client typescript --output client/api.ts
1403
+ rapitapir generate client python --output client/api.py
1404
+
1405
+ # Generate documentation
1406
+ rapitapir generate docs html --output docs/api.html
1407
+ rapitapir generate docs markdown --output API.md
403
1408
  ```
404
1409
 
405
- ## ๐ŸŽจ Examples
1410
+ ### AI-Powered Features
1411
+ ```bash
1412
+ # Generate LLM instructions for specific endpoints
1413
+ rapitapir llm generate --endpoint-id "get_users" --purpose validation
1414
+ rapitapir llm generate --endpoint-id "create_book" --purpose testing
406
1415
 
407
- Explore our comprehensive examples:
1416
+ # Export LLM instructions for all endpoints
1417
+ rapitapir llm export --format instructions --output ai-prompts/
408
1418
 
409
- - **[Hello World](examples/hello_world.rb)** - Minimal API with SinatraRapiTapir base class
410
- - **[Getting Started](examples/getting_started_extension.rb)** - Complete bookstore API with CRUD operations
411
- - **[Enterprise API](examples/enterprise_rapitapir_api.rb)** - Production-ready example with auth
412
- - **[Authentication](examples/authentication_example.rb)** - Bearer token and scope-based auth
413
- - **[Observability](examples/observability/)** - Health checks, metrics, and tracing
1419
+ # Test LLM instruction generation
1420
+ rapitapir llm test --endpoint-file my_api.rb
414
1421
 
415
- ## ๐Ÿ“š Documentation
1422
+ # Export Model Context Protocol for AI agents
1423
+ rapitapir mcp export --output mcp-context.json --format compact
1424
+ ```
416
1425
 
417
- - **[API Reference](docs/endpoint-definition.md)** - Complete endpoint definition guide
418
- - **[SinatraRapiTapir Base Class](docs/sinatra_rapitapir.md)** - Clean inheritance syntax guide
419
- - **[Sinatra Extension](docs/SINATRA_EXTENSION.md)** - Detailed Sinatra integration
420
- - **[Type System](docs/types.md)** - All available types and validations (use `T.` shortcut!)
421
- - **[Authentication](docs/authentication.md)** - Security and auth patterns
422
- - **[Observability](docs/observability.md)** - Monitoring and health checks
423
- - **[GitHub Pages Setup](docs/github_pages_setup.md)** - Documentation deployment guide
1426
+ ### Development & Validation
1427
+ ```bash
1428
+ # Validate endpoint definitions
1429
+ rapitapir validate endpoints --file my_api.rb
1430
+ rapitapir validate openapi --file api-spec.json
1431
+
1432
+ # Serve documentation and specs
1433
+ rapitapir serve --port 3000 --docs-path /documentation
1434
+ rapitapir docs --serve --port 8080 --watch
1435
+
1436
+ # Project scaffolding (coming soon)
1437
+ rapitapir new my-api --template sinatra-ai
1438
+ rapitapir generate scaffold books --with-auth --with-observability
1439
+ ```
424
1440
 
425
- ## ๐Ÿงช Testing
1441
+ ### Installation & Setup
426
1442
 
427
- RapiTapir includes comprehensive testing utilities:
1443
+ ```bash
1444
+ # Install the gem
1445
+ gem install rapitapir
1446
+
1447
+ # Or add to Gemfile
1448
+ echo 'gem "rapitapir"' >> Gemfile
1449
+ bundle install
428
1450
 
1451
+ # Verify installation
1452
+ rapitapir --version
1453
+ rapitapir --help
1454
+ ```
1455
+
1456
+ ## ๐Ÿงช Testing & Quality
1457
+
1458
+ RapiTapir includes comprehensive testing utilities and maintains high code quality:
1459
+
1460
+ ### Test Your APIs
429
1461
  ```ruby
430
- # Validate your endpoint definitions
1462
+ # Validate endpoint definitions
431
1463
  RapiTapir::CLI::Validator.new(endpoints).validate
432
1464
 
433
- # Generate test fixtures
434
- RapiTapir::Testing.generate_fixtures(USER_SCHEMA)
1465
+ # Generate test fixtures from schemas
1466
+ test_user = RapiTapir::Testing.generate_fixture(USER_SCHEMA)
1467
+ test_data = RapiTapir::Testing.generate_fixtures(BOOK_SCHEMA, count: 10)
1468
+
1469
+ # Test endpoint types and validation
1470
+ endpoint.validate!({ name: "test", age: 25 }) # Returns validated data
435
1471
  ```
436
1472
 
437
- Run the test suite:
1473
+ ### Quality Metrics
1474
+ - **643 tests passing** with comprehensive coverage
1475
+ - **67.67% line coverage** across the entire codebase
1476
+ - **RuboCop compliance** with zero style violations
1477
+ - **Zero security vulnerabilities** in dependencies
1478
+ - **Continuous integration** with GitHub Actions
438
1479
 
1480
+ ### Run Tests Locally
439
1481
  ```bash
1482
+ # Clone the repository
1483
+ git clone https://github.com/riccardomerolla/rapitapir.git
1484
+ cd rapitapir
1485
+
1486
+ # Install dependencies
1487
+ bundle install
1488
+
1489
+ # Run the test suite
440
1490
  bundle exec rspec
1491
+
1492
+ # Check code style
1493
+ rubocop
1494
+
1495
+ # View coverage report
1496
+ open coverage/index.html
441
1497
  ```
442
1498
 
443
1499
  ## ๐Ÿค Contributing
444
1500
 
445
- We love contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
446
-
447
- ### Development Setup
1501
+ We love contributions! RapiTapir thrives on community input and collaboration.
448
1502
 
1503
+ ### Quick Start Contributing
449
1504
  ```bash
450
1505
  git clone https://github.com/riccardomerolla/rapitapir.git
451
- cd ruby-tapir
1506
+ cd rapitapir
452
1507
  bundle install
453
- bundle exec rspec
1508
+ bundle exec rspec # Ensure all tests pass
454
1509
  ```
455
1510
 
456
- ### Roadmap
1511
+ ### Ways to Contribute
1512
+ - **๐Ÿ› Bug Reports**: [Open an issue](https://github.com/riccardomerolla/rapitapir/issues/new)
1513
+ - **๐Ÿ’ก Feature Requests**: [Start a discussion](https://github.com/riccardomerolla/rapitapir/discussions)
1514
+ - **๐Ÿ“– Documentation**: Improve guides, examples, and API docs
1515
+ - **๐Ÿงช Tests**: Add test coverage for edge cases
1516
+ - **๐ŸŽจ Examples**: Create real-world API examples
1517
+ - **๐Ÿ”Œ Integrations**: Build plugins for other frameworks
1518
+
1519
+ ### Development Roadmap
457
1520
 
458
- - **Phase 4**: Advanced client generation (Python, Go, etc.)
459
- - **Phase 5**: GraphQL integration
460
- - **Phase 6**: gRPC support
461
- - **Community**: Plugin ecosystem
1521
+ **Current Focus (v2.1)**:
1522
+ - Enhanced AI features and LLM provider support
1523
+ - Advanced authentication patterns
1524
+ - Performance optimizations and caching
1525
+ - Extended CLI functionality
462
1526
 
463
- ## ๏ฟฝ License
1527
+ **Upcoming (v3.0)**:
1528
+ - GraphQL integration alongside REST
1529
+ - gRPC support for high-performance APIs
1530
+ - Advanced plugin ecosystem
1531
+ - Multi-language client generation
464
1532
 
465
- RapiTapir is released under the [MIT License](LICENSE).
1533
+ See our [Contributing Guide](CONTRIBUTING.md) for detailed guidelines.
466
1534
 
467
- ## ๐Ÿ™‹โ€โ™‚๏ธ Support
1535
+ ## ๐Ÿ™‹โ€โ™‚๏ธ Support & Community
468
1536
 
1537
+ ### Get Help
469
1538
  - **๐Ÿ› Bug Reports**: [GitHub Issues](https://github.com/riccardomerolla/rapitapir/issues)
470
- - **๐Ÿ’ก Feature Requests**: [GitHub Discussions](https://github.com/riccardomerolla/rapitapir/discussions)
471
- - **๐Ÿ“ง Email**: riccardo.merolla@gmail.com
1539
+ - **๏ฟฝ Questions & Discussions**: [GitHub Discussions](https://github.com/riccardomerolla/rapitapir/discussions)
1540
+ - **๐Ÿ“ง Direct Contact**: riccardo.merolla@gmail.com
1541
+ - **๐Ÿ“– Documentation**: Comprehensive guides in the [docs/](docs/) directory
1542
+
1543
+ ### Community
1544
+ - **โญ Star the Project**: Show your support on [GitHub](https://github.com/riccardomerolla/rapitapir)
1545
+ - **๐Ÿ”— Share**: Help others discover RapiTapir
1546
+ - **๐Ÿค Contribute**: Join the growing community of contributors
472
1547
 
473
1548
  ---
474
1549
 
475
- **Built with โค๏ธ for the Ruby and Sinatra community**
1550
+ ## ๐Ÿ“œ License
476
1551
 
1552
+ RapiTapir is released under the [MIT License](LICENSE). Use it freely in personal and commercial projects.
477
1553
 
478
1554
  ## ๐Ÿ™ Acknowledgments
479
1555
 
480
- Inspired by:
481
- - [Scala Tapir](https://github.com/softwaremill/tapir) - Type-safe endpoints
1556
+ RapiTapir is inspired by excellent projects in the API development space:
1557
+
1558
+ - **[Scala Tapir](https://github.com/softwaremill/tapir)** - Type-safe endpoint definitions that inspired our DSL
1559
+ - **[FastAPI](https://fastapi.tiangolo.com/)** - Automatic documentation and validation patterns
1560
+ - **[Ruby on Rails](https://rubyonrails.org/)** - Convention over configuration philosophy
1561
+ - **[Sinatra](http://sinatrarb.com/)** - Minimalist web framework elegance
1562
+
1563
+ Special thanks to the Ruby and Sinatra communities for their ongoing support and feedback.
482
1564
 
483
1565
  ---
484
1566
 
485
- **RapiTapir** - APIs so fast and clean, they practically run wild! ๐Ÿฆ™โšก
1567
+ **RapiTapir ๐Ÿฆ™** - *APIs so fast, clean, and intelligent, they practically run wild!* โšก๏ฟฝ
1568
+
1569
+ **Built with โค๏ธ for the Ruby community**