rapitapir 0.1.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +57 -0
- data/CHANGELOG.md +94 -0
- data/CLEANUP_SUMMARY.md +155 -0
- data/CONTRIBUTING.md +280 -0
- data/LICENSE +21 -0
- data/README.md +485 -0
- data/debug_hash.rb +20 -0
- data/docs/EXTENSION_COMPARISON.md +388 -0
- data/docs/SINATRA_EXTENSION.md +467 -0
- data/docs/archive/PHASE_1_2_COMPLETE.md +77 -0
- data/docs/archive/PHASE_1_3_COMPLETE.md +152 -0
- data/docs/archive/PHASE_2_1_OBSERVABILITY_COMPLETED.md +203 -0
- data/docs/archive/PHASE_2_SUMMARY.md +209 -0
- data/docs/archive/REFACTORING_SUMMARY.md +184 -0
- data/docs/archive/phase_1_3_plan.md +136 -0
- data/docs/archive/sinatra_extension_summary.md +188 -0
- data/docs/archive/sinatra_working_solution.md +113 -0
- data/docs/archive/typescript-client-generator-summary.md +259 -0
- data/docs/auto-derivation.md +146 -0
- data/docs/blueprint.md +1091 -0
- data/docs/endpoint-definition.md +211 -0
- data/docs/github_pages_fix.md +52 -0
- data/docs/github_pages_setup.md +49 -0
- data/docs/implementation-status.md +357 -0
- data/docs/observability.md +647 -0
- data/docs/phase3-plan.md +108 -0
- data/docs/sinatra_rapitapir.md +87 -0
- data/docs/type_shortcuts.md +146 -0
- data/examples/README_ENTERPRISE.md +202 -0
- data/examples/authentication_example.rb +192 -0
- data/examples/auto_derivation_ruby_friendly.rb +163 -0
- data/examples/cli/user_api_endpoints.rb +56 -0
- data/examples/client/typescript_client_example.rb +102 -0
- data/examples/client/user-api-client.ts +193 -0
- data/examples/demo_api.rb +41 -0
- data/examples/docs/documentation_example.rb +112 -0
- data/examples/docs/user-api-docs.html +789 -0
- data/examples/docs/user-api-docs.md +403 -0
- data/examples/enhanced_auto_derivation_test.rb +83 -0
- data/examples/enterprise_extension_demo.rb +417 -0
- data/examples/enterprise_rapitapir_api.rb +662 -0
- data/examples/getting_started_extension.rb +218 -0
- data/examples/hello_world.rb +74 -0
- data/examples/oauth2/.env.example +19 -0
- data/examples/oauth2/README.md +205 -0
- data/examples/oauth2/generic_oauth2_api.rb +226 -0
- data/examples/oauth2/get_token.rb +72 -0
- data/examples/oauth2/songs_api_with_auth0.rb +320 -0
- data/examples/oauth2/test_api.sh +16 -0
- data/examples/oauth2/test_songs_api.sh +110 -0
- data/examples/observability/.env.example +35 -0
- data/examples/observability/README.md +230 -0
- data/examples/observability/README_HONEYCOMB.md +332 -0
- data/examples/observability/advanced_setup.rb +384 -0
- data/examples/observability/basic_setup.rb +192 -0
- data/examples/observability/complete_test.rb +121 -0
- data/examples/observability/honeycomb_example.rb +523 -0
- data/examples/observability/honeycomb_rapitapir_clean.rb +488 -0
- data/examples/observability/honeycomb_rapitapir_example.rb +523 -0
- data/examples/observability/honeycomb_working_example.rb +489 -0
- data/examples/observability/quick_test.rb +78 -0
- data/examples/observability/simple_test.rb +14 -0
- data/examples/observability/test_honeycomb_demo.rb +354 -0
- data/examples/observability/test_live_honeycomb.rb +111 -0
- data/examples/observability/test_validation.rb +78 -0
- data/examples/observability/test_working_validation.rb +66 -0
- data/examples/openapi/user_api_schema.rb +132 -0
- data/examples/production_ready_example.rb +105 -0
- data/examples/rails/users_controller.rb +146 -0
- data/examples/readme/basic_sinatra_example.rb +128 -0
- data/examples/server/user_api.rb +179 -0
- data/examples/simple_auto_derivation_demo.rb +44 -0
- data/examples/simple_demo_api.rb +18 -0
- data/examples/sinatra/user_app.rb +127 -0
- data/examples/t_shortcut_demo.rb +59 -0
- data/examples/user_api.rb +190 -0
- data/examples/working_getting_started.rb +184 -0
- data/examples/working_simple_example.rb +195 -0
- data/lib/rapitapir/auth/configuration.rb +129 -0
- data/lib/rapitapir/auth/context.rb +122 -0
- data/lib/rapitapir/auth/errors.rb +104 -0
- data/lib/rapitapir/auth/middleware.rb +324 -0
- data/lib/rapitapir/auth/oauth2.rb +350 -0
- data/lib/rapitapir/auth/schemes.rb +420 -0
- data/lib/rapitapir/auth.rb +113 -0
- data/lib/rapitapir/cli/command.rb +535 -0
- data/lib/rapitapir/cli/server.rb +243 -0
- data/lib/rapitapir/cli/validator.rb +373 -0
- data/lib/rapitapir/client/generator_base.rb +272 -0
- data/lib/rapitapir/client/typescript_generator.rb +350 -0
- data/lib/rapitapir/core/endpoint.rb +158 -0
- data/lib/rapitapir/core/enhanced_endpoint.rb +235 -0
- data/lib/rapitapir/core/input.rb +182 -0
- data/lib/rapitapir/core/output.rb +164 -0
- data/lib/rapitapir/core/request.rb +19 -0
- data/lib/rapitapir/core/response.rb +17 -0
- data/lib/rapitapir/docs/html_generator.rb +780 -0
- data/lib/rapitapir/docs/markdown_generator.rb +464 -0
- data/lib/rapitapir/dsl/endpoint_dsl.rb +116 -0
- data/lib/rapitapir/dsl/enhanced_endpoint_dsl.rb +62 -0
- data/lib/rapitapir/dsl/enhanced_input.rb +73 -0
- data/lib/rapitapir/dsl/enhanced_output.rb +63 -0
- data/lib/rapitapir/dsl/enhanced_structures.rb +393 -0
- data/lib/rapitapir/dsl/fluent_dsl.rb +72 -0
- data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +316 -0
- data/lib/rapitapir/dsl/http_verbs.rb +77 -0
- data/lib/rapitapir/dsl/input_methods.rb +47 -0
- data/lib/rapitapir/dsl/observability_methods.rb +81 -0
- data/lib/rapitapir/dsl/output_methods.rb +43 -0
- data/lib/rapitapir/dsl/type_resolution.rb +43 -0
- data/lib/rapitapir/observability/configuration.rb +108 -0
- data/lib/rapitapir/observability/health_check.rb +236 -0
- data/lib/rapitapir/observability/logging.rb +270 -0
- data/lib/rapitapir/observability/metrics.rb +203 -0
- data/lib/rapitapir/observability/middleware.rb +243 -0
- data/lib/rapitapir/observability/tracing.rb +143 -0
- data/lib/rapitapir/observability.rb +28 -0
- data/lib/rapitapir/openapi/schema_generator.rb +403 -0
- data/lib/rapitapir/schema.rb +136 -0
- data/lib/rapitapir/server/enhanced_rack_adapter.rb +379 -0
- data/lib/rapitapir/server/middleware.rb +120 -0
- data/lib/rapitapir/server/path_matcher.rb +45 -0
- data/lib/rapitapir/server/rack_adapter.rb +215 -0
- data/lib/rapitapir/server/rails_adapter.rb +17 -0
- data/lib/rapitapir/server/rails_adapter_class.rb +53 -0
- data/lib/rapitapir/server/rails_controller.rb +72 -0
- data/lib/rapitapir/server/rails_input_processor.rb +73 -0
- data/lib/rapitapir/server/rails_response_handler.rb +29 -0
- data/lib/rapitapir/server/sinatra_adapter.rb +200 -0
- data/lib/rapitapir/server/sinatra_integration.rb +93 -0
- data/lib/rapitapir/sinatra/configuration.rb +91 -0
- data/lib/rapitapir/sinatra/extension.rb +214 -0
- data/lib/rapitapir/sinatra/oauth2_helpers.rb +236 -0
- data/lib/rapitapir/sinatra/resource_builder.rb +152 -0
- data/lib/rapitapir/sinatra/swagger_ui_generator.rb +166 -0
- data/lib/rapitapir/sinatra_rapitapir.rb +40 -0
- data/lib/rapitapir/types/array.rb +163 -0
- data/lib/rapitapir/types/auto_derivation.rb +265 -0
- data/lib/rapitapir/types/base.rb +146 -0
- data/lib/rapitapir/types/boolean.rb +46 -0
- data/lib/rapitapir/types/date.rb +92 -0
- data/lib/rapitapir/types/datetime.rb +98 -0
- data/lib/rapitapir/types/email.rb +32 -0
- data/lib/rapitapir/types/float.rb +134 -0
- data/lib/rapitapir/types/hash.rb +161 -0
- data/lib/rapitapir/types/integer.rb +143 -0
- data/lib/rapitapir/types/object.rb +156 -0
- data/lib/rapitapir/types/optional.rb +65 -0
- data/lib/rapitapir/types/string.rb +185 -0
- data/lib/rapitapir/types/uuid.rb +32 -0
- data/lib/rapitapir/types.rb +155 -0
- data/lib/rapitapir/version.rb +5 -0
- data/lib/rapitapir.rb +173 -0
- data/rapitapir.gemspec +66 -0
- metadata +387 -0
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module RapiTapir
|
6
|
+
module Core
|
7
|
+
# Output format definition for HTTP endpoints
|
8
|
+
#
|
9
|
+
# Represents different types of response outputs that an endpoint can produce,
|
10
|
+
# including JSON responses, XML responses, status codes, and headers.
|
11
|
+
#
|
12
|
+
# @example JSON response
|
13
|
+
# RapiTapir::Core::Output.new(kind: :json, type: user_schema)
|
14
|
+
#
|
15
|
+
# @example Status response
|
16
|
+
# RapiTapir::Core::Output.new(kind: :status, type: 404)
|
17
|
+
class Output
|
18
|
+
VALID_KINDS = %i[json xml status header].freeze
|
19
|
+
|
20
|
+
attr_reader :kind, :type, :options
|
21
|
+
|
22
|
+
def initialize(kind:, type:, options: {})
|
23
|
+
@kind = kind
|
24
|
+
@type = type
|
25
|
+
validate_kind!(kind)
|
26
|
+
validate_type!(type)
|
27
|
+
@options = options.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def valid_type?(value)
|
31
|
+
case type
|
32
|
+
when :string then value.is_a?(String)
|
33
|
+
when :integer then integer_type?(value)
|
34
|
+
when :float then float_type?(value)
|
35
|
+
when :boolean then boolean_type?(value)
|
36
|
+
when Hash then validate_hash_schema(value)
|
37
|
+
when Class then value.is_a?(type)
|
38
|
+
else true # Accept any for custom types and status codes
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def integer_type?(value)
|
43
|
+
value.is_a?(Integer) || value.is_a?(Float)
|
44
|
+
end
|
45
|
+
|
46
|
+
def float_type?(value)
|
47
|
+
value.is_a?(Float) || value.is_a?(Integer)
|
48
|
+
end
|
49
|
+
|
50
|
+
def serialize(value)
|
51
|
+
case kind
|
52
|
+
when :json then serialize_json(value)
|
53
|
+
when :xml then serialize_xml(value)
|
54
|
+
when :status then value.to_i
|
55
|
+
when :header then value.to_s
|
56
|
+
else value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_h
|
61
|
+
{
|
62
|
+
kind: kind,
|
63
|
+
type: type,
|
64
|
+
options: options
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def validate_kind!(kind)
|
71
|
+
return if VALID_KINDS.include?(kind)
|
72
|
+
|
73
|
+
raise ArgumentError, "Invalid kind: #{kind}. Must be one of #{VALID_KINDS}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_type!(type)
|
77
|
+
case kind
|
78
|
+
when :status
|
79
|
+
validate_status_type!(type)
|
80
|
+
when :json, :xml
|
81
|
+
# Allow any type for JSON/XML bodies
|
82
|
+
when :header
|
83
|
+
validate_header_type!(type)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate_status_type!(type)
|
88
|
+
return if type.is_a?(Integer) && type >= 100 && type <= 599
|
89
|
+
|
90
|
+
raise ArgumentError, "Status type must be an integer between 100-599, got: #{type}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_header_type!(type)
|
94
|
+
return if [:string, String].include?(type) || type.is_a?(Class)
|
95
|
+
|
96
|
+
raise ArgumentError, "Header type must be :string or a Class, got: #{type}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def validate_hash_schema(value)
|
100
|
+
return false unless value.is_a?(Hash)
|
101
|
+
return true unless type.is_a?(Hash) # If type is not a hash schema, accept any hash
|
102
|
+
|
103
|
+
type.all? do |key, expected_type|
|
104
|
+
valid_field_type?(value[key], expected_type)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def valid_field_type?(field_value, expected_type)
|
109
|
+
case expected_type
|
110
|
+
when :string then field_value.is_a?(String)
|
111
|
+
when :integer then field_value.is_a?(Integer)
|
112
|
+
when :float then numeric_type?(field_value)
|
113
|
+
when :boolean then boolean_type?(field_value)
|
114
|
+
when :date then date_type?(field_value)
|
115
|
+
when :datetime then datetime_type?(field_value)
|
116
|
+
else true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def numeric_type?(field_value)
|
121
|
+
field_value.is_a?(Float) || field_value.is_a?(Integer)
|
122
|
+
end
|
123
|
+
|
124
|
+
def boolean_type?(field_value)
|
125
|
+
[true, false].include?(field_value)
|
126
|
+
end
|
127
|
+
|
128
|
+
def date_type?(field_value)
|
129
|
+
field_value.is_a?(Date) || field_value.is_a?(String)
|
130
|
+
end
|
131
|
+
|
132
|
+
def datetime_type?(field_value)
|
133
|
+
field_value.is_a?(DateTime) || field_value.is_a?(String)
|
134
|
+
end
|
135
|
+
|
136
|
+
def serialize_json(value)
|
137
|
+
case value
|
138
|
+
when String then value
|
139
|
+
else JSON.generate(value)
|
140
|
+
end
|
141
|
+
rescue JSON::GeneratorError, JSON::NestingError => e
|
142
|
+
raise TypeError, "Cannot serialize value to JSON: #{e.message}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def serialize_xml(value)
|
146
|
+
# Basic XML serialization - would need a proper XML library in practice
|
147
|
+
case value
|
148
|
+
when String then value
|
149
|
+
when Hash then hash_to_xml(value)
|
150
|
+
else value.to_s
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def hash_to_xml(hash, root = 'root')
|
155
|
+
xml = "<#{root}>"
|
156
|
+
hash.each do |key, value|
|
157
|
+
xml += "<#{key}>#{value}</#{key}>"
|
158
|
+
end
|
159
|
+
xml += "</#{root}>"
|
160
|
+
xml
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RapiTapir
|
4
|
+
module Core
|
5
|
+
# HTTP request wrapper for RapiTapir endpoints
|
6
|
+
# Provides a standardized interface for HTTP request data
|
7
|
+
class Request
|
8
|
+
attr_reader :method, :path, :headers, :params, :body
|
9
|
+
|
10
|
+
def initialize(method:, path:, headers: {}, params: {}, body: nil)
|
11
|
+
@method = method
|
12
|
+
@path = path
|
13
|
+
@headers = headers.freeze
|
14
|
+
@params = params.freeze
|
15
|
+
@body = body
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RapiTapir
|
4
|
+
module Core
|
5
|
+
# HTTP response wrapper for RapiTapir endpoints
|
6
|
+
# Provides a standardized interface for HTTP response data
|
7
|
+
class Response
|
8
|
+
attr_reader :status, :headers, :body
|
9
|
+
|
10
|
+
def initialize(status:, headers: {}, body: nil)
|
11
|
+
@status = status
|
12
|
+
@headers = headers.freeze
|
13
|
+
@body = body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|