1010require_relative "../core/logger_factory"
1111require_relative "../core/log"
1212
13- # import all core endpoint classes dynamically
14- Dir [ File . join ( __dir__ , "endpoints/**/*.rb" ) ] . sort . each do |file |
15- require file
16- end
13+ # Import all core endpoint classes dynamically
14+ Dir [ File . join ( __dir__ , "endpoints/**/*.rb" ) ] . sort . each { |file | require file }
1715
1816module Hooks
1917 module App
@@ -22,58 +20,37 @@ class API
2220 include Hooks ::App ::Helpers
2321 include Hooks ::App ::Auth
2422
25- # Expose start_time for endpoint modules
26- def self . start_time
27- @start_time
23+ class << self
24+ attr_reader :start_time
2825 end
2926
3027 # Create a new configured API class
3128 def self . create ( config :, endpoints :, log :)
32- # Store startup time for uptime calculation
3329 @start_time = Time . now
3430
35- # Capture values in local variables for closure
36- captured_config = config
37- captured_endpoints = endpoints
38- captured_logger = log
39-
40- # Set global logger instance for plugins/validators
4131 Hooks ::Log . instance = log
4232
43- # Create the API class with dynamic routes
4433 api_class = Class . new ( Grape ::API ) do
45- # Accept all content types but don't auto-parse
4634 content_type :json , "application/json"
4735 content_type :txt , "text/plain"
4836 content_type :xml , "application/xml"
4937 content_type :any , "*/*"
50- format :txt # Use text format so no automatic parsing happens
38+ format :txt
5139 default_format :txt
5240 end
5341
54- # Use class_eval to dynamically define routes
5542 api_class . class_eval do
56- # Define helper methods first, before routes
5743 helpers Helpers , Auth
5844
59- # Mount core operational endpoints
6045 mount Hooks ::App ::HealthEndpoint => config [ :health_path ]
6146 mount Hooks ::App ::VersionEndpoint => config [ :version_path ]
6247
63- # Define webhook endpoints dynamically
64- captured_endpoints . each do |endpoint_config |
65- full_path = "#{ captured_config [ :root_path ] } #{ endpoint_config [ :path ] } "
48+ endpoints . each do |endpoint_config |
49+ full_path = "#{ config [ :root_path ] } #{ endpoint_config [ :path ] } "
6650 handler_class_name = endpoint_config [ :handler ]
6751
68- # Use send to dynamically create POST route
69- send ( :post , full_path ) do
52+ post ( full_path ) do
7053 request_id = uuid
71-
72- # Use captured values
73- config = captured_config
74- log = captured_logger
75-
76- # Set request context for logging
7754 request_context = {
7855 request_id :,
7956 path : full_path ,
@@ -82,57 +59,37 @@ def self.create(config:, endpoints:, log:)
8259
8360 Core ::LogContext . with ( request_context ) do
8461 begin
85- # Enforce request limits
8662 enforce_request_limits ( config )
87-
88- # Get raw body for signature validation
8963 request . body . rewind
9064 raw_body = request . body . read
9165
92- # Verify/validate request if configured
9366 if endpoint_config [ :auth ]
9467 log . info "validating request (id: #{ request_id } , handler: #{ handler_class_name } )"
95- validate_auth! ( raw_body , headers , endpoint_config ) if endpoint_config [ :auth ]
68+ validate_auth! ( raw_body , headers , endpoint_config )
9669 end
9770
98- # Parse payload (symbolize_payload is true by default)
9971 payload = parse_payload ( raw_body , headers , symbolize : config [ :symbolize_payload ] )
100-
101- # Load and instantiate handler
10272 handler = load_handler ( handler_class_name , config [ :handler_dir ] )
73+ normalized_headers = config [ :normalize_headers ] ? Hooks ::Utils ::Normalize . headers ( headers ) : headers
10374
104- # Normalize the headers based on the endpoint configuration (normalization is the default)
105- headers = Hooks ::Utils ::Normalize . headers ( headers ) if config [ :normalize_headers ]
106-
107- # Call handler
10875 response = handler . call (
10976 payload :,
110- headers :,
77+ headers : normalized_headers ,
11178 config : endpoint_config
11279 )
11380
11481 log . info "request processed successfully (id: #{ request_id } , handler: #{ handler_class_name } )"
115-
116- # Return response as JSON string when using txt format
117- status 200 # Explicitly set status to 200
82+ status 200
11883 content_type "application/json"
11984 ( response || { status : "ok" } ) . to_json
120-
12185 rescue => e
12286 log . error "request failed: #{ e . message } (id: #{ request_id } , handler: #{ handler_class_name } )"
123-
124- # Return error response
12587 error_response = {
12688 error : e . message ,
12789 code : determine_error_code ( e ) ,
128- request_id :
90+ request_id : request_id
12991 }
130-
131- # Add backtrace in all environments except production
132- unless config [ :production ] == true
133- error_response [ :backtrace ] = e . backtrace
134- end
135-
92+ error_response [ :backtrace ] = e . backtrace unless config [ :production ]
13693 status error_response [ :code ]
13794 content_type "application/json"
13895 error_response . to_json
@@ -141,16 +98,13 @@ def self.create(config:, endpoints:, log:)
14198 end
14299 end
143100
144- # Catch-all route for unknown endpoints - use default handler
145- # Only create if explicitly enabled in config
146- if captured_config [ :use_catchall_route ]
147- route_path = Hooks ::App ::CatchallEndpoint . mount_path ( captured_config )
148- route_block = Hooks ::App ::CatchallEndpoint . route_block ( captured_config , captured_logger )
101+ if config [ :use_catchall_route ]
102+ route_path = Hooks ::App ::CatchallEndpoint . mount_path ( config )
103+ route_block = Hooks ::App ::CatchallEndpoint . route_block ( config , log )
149104 post ( route_path , &route_block )
150105 end
151106 end
152107
153- # Return the configured API class
154108 api_class
155109 end
156110 end
0 commit comments