spikard 0.13.0 → 0.15.2

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 (207) hide show
  1. checksums.yaml +4 -4
  2. data/Steepfile +6 -0
  3. data/ext/spikard_rb/extconf.rb +1 -2
  4. data/ext/spikard_rb/{Cargo.lock → native/Cargo.lock} +819 -424
  5. data/ext/spikard_rb/native/Cargo.toml +24 -0
  6. data/ext/spikard_rb/src/lib.rs +5366 -3
  7. data/lib/spikard/native.rb +86 -0
  8. data/lib/spikard/version.rb +6 -1
  9. data/lib/spikard.rb +8 -52
  10. data/lib/spikard_rb.so +0 -0
  11. data/sig/types.rbs +427 -0
  12. metadata +14 -243
  13. data/LICENSE +0 -1
  14. data/README.md +0 -285
  15. data/ext/spikard_rb/Cargo.toml +0 -17
  16. data/lib/spikard/app.rb +0 -458
  17. data/lib/spikard/background.rb +0 -58
  18. data/lib/spikard/config.rb +0 -506
  19. data/lib/spikard/converters.rb +0 -13
  20. data/lib/spikard/grpc.rb +0 -232
  21. data/lib/spikard/handler_wrapper.rb +0 -113
  22. data/lib/spikard/provide.rb +0 -315
  23. data/lib/spikard/response.rb +0 -198
  24. data/lib/spikard/schema.rb +0 -243
  25. data/lib/spikard/sse.rb +0 -111
  26. data/lib/spikard/streaming_response.rb +0 -44
  27. data/lib/spikard/testing.rb +0 -474
  28. data/lib/spikard/upload_file.rb +0 -131
  29. data/lib/spikard/websocket.rb +0 -59
  30. data/sig/spikard.rbs +0 -739
  31. data/vendor/crates/spikard-bindings-shared/Cargo.toml +0 -75
  32. data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +0 -132
  33. data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +0 -905
  34. data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +0 -210
  35. data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +0 -252
  36. data/vendor/crates/spikard-bindings-shared/src/error_response.rs +0 -404
  37. data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +0 -199
  38. data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +0 -252
  39. data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +0 -829
  40. data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +0 -587
  41. data/vendor/crates/spikard-bindings-shared/src/lib.rs +0 -33
  42. data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +0 -298
  43. data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +0 -594
  44. data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +0 -743
  45. data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +0 -944
  46. data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +0 -260
  47. data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +0 -369
  48. data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +0 -192
  49. data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +0 -383
  50. data/vendor/crates/spikard-bindings-shared/tests/full_coverage.rs +0 -459
  51. data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +0 -280
  52. data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +0 -669
  53. data/vendor/crates/spikard-core/Cargo.toml +0 -55
  54. data/vendor/crates/spikard-core/src/bindings/mod.rs +0 -3
  55. data/vendor/crates/spikard-core/src/bindings/response.rs +0 -130
  56. data/vendor/crates/spikard-core/src/debug.rs +0 -127
  57. data/vendor/crates/spikard-core/src/di/container.rs +0 -711
  58. data/vendor/crates/spikard-core/src/di/dependency.rs +0 -273
  59. data/vendor/crates/spikard-core/src/di/error.rs +0 -118
  60. data/vendor/crates/spikard-core/src/di/factory.rs +0 -548
  61. data/vendor/crates/spikard-core/src/di/graph.rs +0 -507
  62. data/vendor/crates/spikard-core/src/di/mod.rs +0 -192
  63. data/vendor/crates/spikard-core/src/di/resolved.rs +0 -428
  64. data/vendor/crates/spikard-core/src/di/value.rs +0 -282
  65. data/vendor/crates/spikard-core/src/errors.rs +0 -72
  66. data/vendor/crates/spikard-core/src/http.rs +0 -492
  67. data/vendor/crates/spikard-core/src/lib.rs +0 -29
  68. data/vendor/crates/spikard-core/src/lifecycle.rs +0 -1273
  69. data/vendor/crates/spikard-core/src/metadata.rs +0 -378
  70. data/vendor/crates/spikard-core/src/parameters.rs +0 -2546
  71. data/vendor/crates/spikard-core/src/problem.rs +0 -358
  72. data/vendor/crates/spikard-core/src/request_data.rs +0 -1146
  73. data/vendor/crates/spikard-core/src/router.rs +0 -530
  74. data/vendor/crates/spikard-core/src/schema_registry.rs +0 -197
  75. data/vendor/crates/spikard-core/src/type_hints.rs +0 -311
  76. data/vendor/crates/spikard-core/src/validation/error_mapper.rs +0 -710
  77. data/vendor/crates/spikard-core/src/validation/mod.rs +0 -470
  78. data/vendor/crates/spikard-core/tests/bindings_response_tests.rs +0 -136
  79. data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +0 -37
  80. data/vendor/crates/spikard-core/tests/error_mapper.rs +0 -761
  81. data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +0 -106
  82. data/vendor/crates/spikard-core/tests/parameters_full.rs +0 -701
  83. data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +0 -301
  84. data/vendor/crates/spikard-core/tests/request_data_roundtrip.rs +0 -67
  85. data/vendor/crates/spikard-core/tests/validation_coverage.rs +0 -250
  86. data/vendor/crates/spikard-core/tests/validation_error_paths.rs +0 -45
  87. data/vendor/crates/spikard-http/Cargo.toml +0 -82
  88. data/vendor/crates/spikard-http/examples/sse-notifications.rs +0 -148
  89. data/vendor/crates/spikard-http/examples/websocket-chat.rs +0 -92
  90. data/vendor/crates/spikard-http/src/auth.rs +0 -301
  91. data/vendor/crates/spikard-http/src/background.rs +0 -1859
  92. data/vendor/crates/spikard-http/src/bindings/mod.rs +0 -3
  93. data/vendor/crates/spikard-http/src/bindings/response.rs +0 -1
  94. data/vendor/crates/spikard-http/src/body_metadata.rs +0 -8
  95. data/vendor/crates/spikard-http/src/cors.rs +0 -1026
  96. data/vendor/crates/spikard-http/src/debug.rs +0 -128
  97. data/vendor/crates/spikard-http/src/di_handler.rs +0 -1672
  98. data/vendor/crates/spikard-http/src/grpc/framing.rs +0 -653
  99. data/vendor/crates/spikard-http/src/grpc/handler.rs +0 -1211
  100. data/vendor/crates/spikard-http/src/grpc/mod.rs +0 -556
  101. data/vendor/crates/spikard-http/src/grpc/service.rs +0 -706
  102. data/vendor/crates/spikard-http/src/grpc/streaming.rs +0 -319
  103. data/vendor/crates/spikard-http/src/handler_response.rs +0 -901
  104. data/vendor/crates/spikard-http/src/handler_trait.rs +0 -1015
  105. data/vendor/crates/spikard-http/src/handler_trait_tests.rs +0 -290
  106. data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +0 -502
  107. data/vendor/crates/spikard-http/src/jsonrpc/method_registry.rs +0 -648
  108. data/vendor/crates/spikard-http/src/jsonrpc/mod.rs +0 -60
  109. data/vendor/crates/spikard-http/src/jsonrpc/openrpc.rs +0 -325
  110. data/vendor/crates/spikard-http/src/jsonrpc/protocol.rs +0 -1207
  111. data/vendor/crates/spikard-http/src/jsonrpc/router.rs +0 -2262
  112. data/vendor/crates/spikard-http/src/lib.rs +0 -566
  113. data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +0 -230
  114. data/vendor/crates/spikard-http/src/lifecycle.rs +0 -1193
  115. data/vendor/crates/spikard-http/src/middleware/mod.rs +0 -560
  116. data/vendor/crates/spikard-http/src/middleware/multipart.rs +0 -912
  117. data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +0 -513
  118. data/vendor/crates/spikard-http/src/middleware/validation.rs +0 -768
  119. data/vendor/crates/spikard-http/src/openapi/mod.rs +0 -309
  120. data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +0 -535
  121. data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +0 -1363
  122. data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +0 -667
  123. data/vendor/crates/spikard-http/src/query_parser.rs +0 -793
  124. data/vendor/crates/spikard-http/src/response.rs +0 -720
  125. data/vendor/crates/spikard-http/src/server/fast_router.rs +0 -186
  126. data/vendor/crates/spikard-http/src/server/grpc_routing.rs +0 -1243
  127. data/vendor/crates/spikard-http/src/server/handler.rs +0 -1661
  128. data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +0 -253
  129. data/vendor/crates/spikard-http/src/server/mod.rs +0 -1717
  130. data/vendor/crates/spikard-http/src/server/request_extraction.rs +0 -871
  131. data/vendor/crates/spikard-http/src/server/routing_factory.rs +0 -618
  132. data/vendor/crates/spikard-http/src/sse.rs +0 -1409
  133. data/vendor/crates/spikard-http/src/testing/form.rs +0 -52
  134. data/vendor/crates/spikard-http/src/testing/multipart.rs +0 -64
  135. data/vendor/crates/spikard-http/src/testing/test_client.rs +0 -825
  136. data/vendor/crates/spikard-http/src/testing.rs +0 -617
  137. data/vendor/crates/spikard-http/src/websocket.rs +0 -1477
  138. data/vendor/crates/spikard-http/tests/auth_integration.rs +0 -645
  139. data/vendor/crates/spikard-http/tests/background_behavior.rs +0 -832
  140. data/vendor/crates/spikard-http/tests/common/grpc_helpers.rs +0 -1012
  141. data/vendor/crates/spikard-http/tests/common/handlers.rs +0 -309
  142. data/vendor/crates/spikard-http/tests/common/mod.rs +0 -33
  143. data/vendor/crates/spikard-http/tests/common/test_builders.rs +0 -628
  144. data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +0 -162
  145. data/vendor/crates/spikard-http/tests/di_integration.rs +0 -192
  146. data/vendor/crates/spikard-http/tests/doc_snippets.rs +0 -5
  147. data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +0 -430
  148. data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +0 -738
  149. data/vendor/crates/spikard-http/tests/grpc_error_handling_test.rs +0 -652
  150. data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +0 -334
  151. data/vendor/crates/spikard-http/tests/grpc_metadata_test.rs +0 -532
  152. data/vendor/crates/spikard-http/tests/grpc_server_integration.rs +0 -495
  153. data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +0 -975
  154. data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +0 -1093
  155. data/vendor/crates/spikard-http/tests/middleware_stack_integration.rs +0 -389
  156. data/vendor/crates/spikard-http/tests/multipart_behavior.rs +0 -656
  157. data/vendor/crates/spikard-http/tests/request_extraction_full.rs +0 -513
  158. data/vendor/crates/spikard-http/tests/server_auth_middleware_behavior.rs +0 -328
  159. data/vendor/crates/spikard-http/tests/server_config_builder.rs +0 -335
  160. data/vendor/crates/spikard-http/tests/server_configured_router_behavior.rs +0 -374
  161. data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +0 -83
  162. data/vendor/crates/spikard-http/tests/server_handler_wrappers.rs +0 -464
  163. data/vendor/crates/spikard-http/tests/server_method_router_additional_behavior.rs +0 -286
  164. data/vendor/crates/spikard-http/tests/server_method_router_coverage.rs +0 -118
  165. data/vendor/crates/spikard-http/tests/server_middleware_behavior.rs +0 -99
  166. data/vendor/crates/spikard-http/tests/server_middleware_branches.rs +0 -204
  167. data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +0 -427
  168. data/vendor/crates/spikard-http/tests/server_router_behavior.rs +0 -121
  169. data/vendor/crates/spikard-http/tests/sse_behavior.rs +0 -620
  170. data/vendor/crates/spikard-http/tests/sse_full_behavior.rs +0 -584
  171. data/vendor/crates/spikard-http/tests/sse_handler_behavior.rs +0 -130
  172. data/vendor/crates/spikard-http/tests/test_client_requests.rs +0 -167
  173. data/vendor/crates/spikard-http/tests/testing_helpers.rs +0 -87
  174. data/vendor/crates/spikard-http/tests/testing_module_coverage.rs +0 -155
  175. data/vendor/crates/spikard-http/tests/urlencoded_content_type.rs +0 -82
  176. data/vendor/crates/spikard-http/tests/websocket_behavior.rs +0 -663
  177. data/vendor/crates/spikard-http/tests/websocket_full_behavior.rs +0 -440
  178. data/vendor/crates/spikard-http/tests/websocket_integration.rs +0 -150
  179. data/vendor/crates/spikard-rb/Cargo.toml +0 -63
  180. data/vendor/crates/spikard-rb/build.rs +0 -200
  181. data/vendor/crates/spikard-rb/src/background.rs +0 -63
  182. data/vendor/crates/spikard-rb/src/config/mod.rs +0 -5
  183. data/vendor/crates/spikard-rb/src/config/server_config.rs +0 -401
  184. data/vendor/crates/spikard-rb/src/conversion.rs +0 -688
  185. data/vendor/crates/spikard-rb/src/di/builder.rs +0 -100
  186. data/vendor/crates/spikard-rb/src/di/mod.rs +0 -410
  187. data/vendor/crates/spikard-rb/src/grpc/handler.rs +0 -875
  188. data/vendor/crates/spikard-rb/src/grpc/mod.rs +0 -13
  189. data/vendor/crates/spikard-rb/src/gvl.rs +0 -80
  190. data/vendor/crates/spikard-rb/src/handler.rs +0 -699
  191. data/vendor/crates/spikard-rb/src/integration/mod.rs +0 -3
  192. data/vendor/crates/spikard-rb/src/lib.rs +0 -2268
  193. data/vendor/crates/spikard-rb/src/lifecycle.rs +0 -334
  194. data/vendor/crates/spikard-rb/src/metadata/mod.rs +0 -5
  195. data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +0 -507
  196. data/vendor/crates/spikard-rb/src/request.rs +0 -439
  197. data/vendor/crates/spikard-rb/src/runtime/mod.rs +0 -5
  198. data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +0 -368
  199. data/vendor/crates/spikard-rb/src/server.rs +0 -304
  200. data/vendor/crates/spikard-rb/src/sse.rs +0 -231
  201. data/vendor/crates/spikard-rb/src/testing/client.rs +0 -698
  202. data/vendor/crates/spikard-rb/src/testing/mod.rs +0 -7
  203. data/vendor/crates/spikard-rb/src/testing/sse.rs +0 -108
  204. data/vendor/crates/spikard-rb/src/testing/websocket.rs +0 -573
  205. data/vendor/crates/spikard-rb/src/websocket.rs +0 -521
  206. data/vendor/crates/spikard-rb-macros/Cargo.toml +0 -20
  207. data/vendor/crates/spikard-rb-macros/src/lib.rs +0 -51
@@ -1,566 +0,0 @@
1
- #![allow(clippy::pedantic, clippy::nursery)]
2
- #![cfg_attr(test, allow(clippy::all))]
3
- //! Spikard HTTP Server
4
- //!
5
- //! Pure Rust HTTP server with language-agnostic handler trait.
6
- //! Language bindings (Python, Node, WASM) implement the Handler trait.
7
-
8
- pub mod auth;
9
- pub mod background;
10
- pub mod bindings;
11
- pub mod body_metadata;
12
- pub mod cors;
13
- pub mod debug;
14
- #[cfg(feature = "di")]
15
- pub mod di_handler;
16
- pub mod grpc;
17
- pub mod handler_response;
18
- pub mod handler_trait;
19
- pub mod jsonrpc;
20
- pub mod lifecycle;
21
- pub mod middleware;
22
- pub mod openapi;
23
- pub mod query_parser;
24
- pub mod response;
25
- pub mod server;
26
- pub mod sse;
27
- pub mod testing;
28
- pub mod websocket;
29
-
30
- use serde::{Deserialize, Serialize};
31
- use tokio::runtime::Runtime;
32
-
33
- #[cfg(test)]
34
- mod handler_trait_tests;
35
-
36
- pub use auth::{Claims, api_key_auth_middleware, jwt_auth_middleware};
37
- pub use background::{
38
- BackgroundHandle, BackgroundJobError, BackgroundJobMetadata, BackgroundRuntime, BackgroundSpawnError,
39
- BackgroundTaskConfig,
40
- };
41
- pub use body_metadata::ResponseBodySize;
42
- #[cfg(feature = "di")]
43
- pub use di_handler::DependencyInjectingHandler;
44
- pub use grpc::{
45
- GrpcConfig, GrpcHandler, GrpcHandlerResult, GrpcRegistry, GrpcRequestData, GrpcResponseData, MessageStream,
46
- StreamingRequest, StreamingResponse,
47
- };
48
- pub use handler_response::HandlerResponse;
49
- pub use handler_trait::{Handler, HandlerResult, RequestData, StaticResponse, StaticResponseHandler, ValidatedParams};
50
- pub use jsonrpc::JsonRpcConfig;
51
- pub use lifecycle::{HookResult, LifecycleHook, LifecycleHooks, LifecycleHooksBuilder, request_hook, response_hook};
52
- pub use openapi::{ContactInfo, LicenseInfo, OpenApiConfig, SecuritySchemeInfo, ServerInfo};
53
- pub use response::Response;
54
- pub use server::Server;
55
- pub use spikard_core::{
56
- CompressionConfig, CorsConfig, Method, ParameterValidator, ProblemDetails, RateLimitConfig, Route, RouteHandler,
57
- RouteMetadata, Router, SchemaRegistry, SchemaValidator,
58
- };
59
- pub use sse::{SseEvent, SseEventProducer, SseState, sse_handler};
60
- pub use testing::{ResponseSnapshot, SnapshotError, snapshot_response};
61
- pub use websocket::{WebSocketHandler, WebSocketState, websocket_handler};
62
-
63
- /// Reexport from spikard_core for convenience
64
- pub use spikard_core::problem::CONTENT_TYPE_PROBLEM_JSON;
65
-
66
- /// JWT authentication configuration
67
- #[derive(Debug, Clone, Serialize, Deserialize)]
68
- pub struct JwtConfig {
69
- /// Secret key for JWT verification
70
- pub secret: String,
71
- /// Required algorithm (HS256, HS384, HS512, RS256, etc.)
72
- #[serde(default = "default_jwt_algorithm")]
73
- pub algorithm: String,
74
- /// Required audience claim
75
- pub audience: Option<Vec<String>>,
76
- /// Required issuer claim
77
- pub issuer: Option<String>,
78
- /// Leeway for expiration checks (seconds)
79
- #[serde(default)]
80
- pub leeway: u64,
81
- }
82
-
83
- fn default_jwt_algorithm() -> String {
84
- "HS256".to_string()
85
- }
86
-
87
- /// API Key authentication configuration
88
- #[derive(Debug, Clone, Serialize, Deserialize)]
89
- pub struct ApiKeyConfig {
90
- /// Valid API keys
91
- pub keys: Vec<String>,
92
- /// Header name to check (e.g., "X-API-Key")
93
- #[serde(default = "default_api_key_header")]
94
- pub header_name: String,
95
- }
96
-
97
- fn default_api_key_header() -> String {
98
- "X-API-Key".to_string()
99
- }
100
-
101
- /// Static file serving configuration
102
- #[derive(Debug, Clone, Serialize, Deserialize)]
103
- pub struct StaticFilesConfig {
104
- /// Directory path to serve
105
- pub directory: String,
106
- /// URL path prefix (e.g., "/static")
107
- pub route_prefix: String,
108
- /// Fallback to index.html for directories
109
- #[serde(default = "default_true")]
110
- pub index_file: bool,
111
- /// Cache-Control header value
112
- pub cache_control: Option<String>,
113
- }
114
-
115
- /// Server configuration
116
- #[derive(Debug, Clone)]
117
- pub struct ServerConfig {
118
- /// Host to bind to
119
- pub host: String,
120
- /// Port to bind to
121
- pub port: u16,
122
- /// Number of Tokio runtime worker threads used by binding-managed server runtimes
123
- pub workers: usize,
124
-
125
- /// Enable request ID generation and propagation
126
- pub enable_request_id: bool,
127
- /// Maximum request body size in bytes (None = unlimited, not recommended)
128
- pub max_body_size: Option<usize>,
129
- /// Request timeout in seconds (None = no timeout)
130
- pub request_timeout: Option<u64>,
131
- /// Enable compression middleware
132
- pub compression: Option<CompressionConfig>,
133
- /// Enable rate limiting
134
- pub rate_limit: Option<RateLimitConfig>,
135
- /// JWT authentication configuration
136
- pub jwt_auth: Option<JwtConfig>,
137
- /// API Key authentication configuration
138
- pub api_key_auth: Option<ApiKeyConfig>,
139
- /// Static file serving configuration
140
- pub static_files: Vec<StaticFilesConfig>,
141
- /// Enable graceful shutdown on SIGTERM/SIGINT
142
- pub graceful_shutdown: bool,
143
- /// Graceful shutdown timeout (seconds)
144
- pub shutdown_timeout: u64,
145
- /// OpenAPI documentation configuration
146
- pub openapi: Option<crate::openapi::OpenApiConfig>,
147
- /// JSON-RPC configuration
148
- pub jsonrpc: Option<crate::jsonrpc::JsonRpcConfig>,
149
- /// gRPC configuration
150
- pub grpc: Option<crate::grpc::GrpcConfig>,
151
- /// Lifecycle hooks for request/response processing
152
- pub lifecycle_hooks: Option<std::sync::Arc<LifecycleHooks>>,
153
- /// Background task executor configuration
154
- pub background_tasks: BackgroundTaskConfig,
155
- /// Enable per-request HTTP tracing (tower-http `TraceLayer`)
156
- pub enable_http_trace: bool,
157
- /// Dependency injection container (requires 'di' feature)
158
- #[cfg(feature = "di")]
159
- pub di_container: Option<std::sync::Arc<spikard_core::di::DependencyContainer>>,
160
- }
161
-
162
- impl Default for ServerConfig {
163
- fn default() -> Self {
164
- Self {
165
- host: "127.0.0.1".to_string(),
166
- port: 8000,
167
- workers: 1,
168
- enable_request_id: false,
169
- max_body_size: Some(10 * 1024 * 1024),
170
- request_timeout: None,
171
- compression: None,
172
- rate_limit: None,
173
- jwt_auth: None,
174
- api_key_auth: None,
175
- static_files: Vec::new(),
176
- graceful_shutdown: true,
177
- shutdown_timeout: 30,
178
- openapi: None,
179
- jsonrpc: None,
180
- grpc: None,
181
- lifecycle_hooks: None,
182
- background_tasks: BackgroundTaskConfig::default(),
183
- enable_http_trace: false,
184
- #[cfg(feature = "di")]
185
- di_container: None,
186
- }
187
- }
188
- }
189
-
190
- impl ServerConfig {
191
- /// Create a new builder for ServerConfig
192
- ///
193
- /// # Example
194
- ///
195
- /// ```ignorerust
196
- /// use spikard_http::ServerConfig;
197
- ///
198
- /// let config = ServerConfig::builder()
199
- /// .port(3000)
200
- /// .host("0.0.0.0")
201
- /// .build();
202
- /// ```
203
- pub fn builder() -> ServerConfigBuilder {
204
- ServerConfigBuilder::default()
205
- }
206
- }
207
-
208
- /// Builder for ServerConfig
209
- ///
210
- /// Provides a fluent API for configuring a Spikard server with dependency injection support.
211
- ///
212
- /// # Dependency Injection
213
- ///
214
- /// The builder provides methods to register dependencies that will be injected into handlers:
215
- ///
216
- /// ```ignorerust
217
- /// # #[cfg(feature = "di")]
218
- /// # {
219
- /// use spikard_http::ServerConfig;
220
- /// use std::sync::Arc;
221
- ///
222
- /// let config = ServerConfig::builder()
223
- /// .port(3000)
224
- /// .provide_value("app_name", "MyApp".to_string())
225
- /// .provide_value("max_connections", 100)
226
- /// .build();
227
- /// # }
228
- /// ```
229
- ///
230
- /// For factory dependencies that create values on-demand:
231
- ///
232
- /// ```ignorerust
233
- /// # #[cfg(feature = "di")]
234
- /// # {
235
- /// use spikard_http::ServerConfig;
236
- ///
237
- /// let config = ServerConfig::builder()
238
- /// .port(3000)
239
- /// .provide_value("db_url", "postgresql://localhost/mydb".to_string())
240
- /// .build();
241
- /// # }
242
- /// ```
243
- #[derive(Debug, Clone, Default)]
244
- pub struct ServerConfigBuilder {
245
- config: ServerConfig,
246
- }
247
-
248
- impl ServerConfigBuilder {
249
- /// Set the host address to bind to
250
- pub fn host(mut self, host: impl Into<String>) -> Self {
251
- self.config.host = host.into();
252
- self
253
- }
254
-
255
- /// Set the port to bind to
256
- pub fn port(mut self, port: u16) -> Self {
257
- self.config.port = port;
258
- self
259
- }
260
-
261
- /// Set the number of Tokio runtime worker threads
262
- pub fn workers(mut self, workers: usize) -> Self {
263
- self.config.workers = workers;
264
- self
265
- }
266
-
267
- /// Enable or disable request ID generation and propagation
268
- pub fn enable_request_id(mut self, enable: bool) -> Self {
269
- self.config.enable_request_id = enable;
270
- self
271
- }
272
-
273
- /// Enable or disable per-request HTTP tracing (tower-http `TraceLayer`)
274
- pub fn enable_http_trace(mut self, enable: bool) -> Self {
275
- self.config.enable_http_trace = enable;
276
- self
277
- }
278
-
279
- /// Set maximum request body size in bytes (None = unlimited, not recommended)
280
- pub fn max_body_size(mut self, size: Option<usize>) -> Self {
281
- self.config.max_body_size = size;
282
- self
283
- }
284
-
285
- /// Set request timeout in seconds (None = no timeout)
286
- pub fn request_timeout(mut self, timeout: Option<u64>) -> Self {
287
- self.config.request_timeout = timeout;
288
- self
289
- }
290
-
291
- /// Set compression configuration
292
- pub fn compression(mut self, compression: Option<CompressionConfig>) -> Self {
293
- self.config.compression = compression;
294
- self
295
- }
296
-
297
- /// Set rate limiting configuration
298
- pub fn rate_limit(mut self, rate_limit: Option<RateLimitConfig>) -> Self {
299
- self.config.rate_limit = rate_limit;
300
- self
301
- }
302
-
303
- /// Set JWT authentication configuration
304
- pub fn jwt_auth(mut self, jwt_auth: Option<JwtConfig>) -> Self {
305
- self.config.jwt_auth = jwt_auth;
306
- self
307
- }
308
-
309
- /// Set API key authentication configuration
310
- pub fn api_key_auth(mut self, api_key_auth: Option<ApiKeyConfig>) -> Self {
311
- self.config.api_key_auth = api_key_auth;
312
- self
313
- }
314
-
315
- /// Add static file serving configuration
316
- pub fn static_files(mut self, static_files: Vec<StaticFilesConfig>) -> Self {
317
- self.config.static_files = static_files;
318
- self
319
- }
320
-
321
- /// Add a single static file serving configuration
322
- pub fn add_static_files(mut self, static_file: StaticFilesConfig) -> Self {
323
- self.config.static_files.push(static_file);
324
- self
325
- }
326
-
327
- /// Enable or disable graceful shutdown on SIGTERM/SIGINT
328
- pub fn graceful_shutdown(mut self, enable: bool) -> Self {
329
- self.config.graceful_shutdown = enable;
330
- self
331
- }
332
-
333
- /// Set graceful shutdown timeout in seconds
334
- pub fn shutdown_timeout(mut self, timeout: u64) -> Self {
335
- self.config.shutdown_timeout = timeout;
336
- self
337
- }
338
-
339
- /// Set OpenAPI documentation configuration
340
- pub fn openapi(mut self, openapi: Option<crate::openapi::OpenApiConfig>) -> Self {
341
- self.config.openapi = openapi;
342
- self
343
- }
344
-
345
- /// Set JSON-RPC configuration
346
- pub fn jsonrpc(mut self, jsonrpc: Option<crate::jsonrpc::JsonRpcConfig>) -> Self {
347
- self.config.jsonrpc = jsonrpc;
348
- self
349
- }
350
-
351
- /// Set gRPC configuration
352
- pub fn grpc(mut self, grpc: Option<crate::grpc::GrpcConfig>) -> Self {
353
- self.config.grpc = grpc;
354
- self
355
- }
356
-
357
- /// Set lifecycle hooks for request/response processing
358
- pub fn lifecycle_hooks(mut self, hooks: Option<std::sync::Arc<LifecycleHooks>>) -> Self {
359
- self.config.lifecycle_hooks = hooks;
360
- self
361
- }
362
-
363
- /// Set background task executor configuration
364
- pub fn background_tasks(mut self, config: BackgroundTaskConfig) -> Self {
365
- self.config.background_tasks = config;
366
- self
367
- }
368
-
369
- /// Register a value dependency (like Fastify decorate)
370
- ///
371
- /// Value dependencies are static values that are cloned when injected into handlers.
372
- /// Use this for configuration objects, constants, or small shared state.
373
- ///
374
- /// # Example
375
- ///
376
- /// ```ignorerust
377
- /// # #[cfg(feature = "di")]
378
- /// # {
379
- /// use spikard_http::ServerConfig;
380
- ///
381
- /// let config = ServerConfig::builder()
382
- /// .provide_value("app_name", "MyApp".to_string())
383
- /// .provide_value("version", "1.0.0".to_string())
384
- /// .provide_value("max_connections", 100)
385
- /// .build();
386
- /// # }
387
- /// ```
388
- #[cfg(feature = "di")]
389
- pub fn provide_value<T: Clone + Send + Sync + 'static>(mut self, key: impl Into<String>, value: T) -> Self {
390
- use spikard_core::di::{DependencyContainer, ValueDependency};
391
- use std::sync::Arc;
392
-
393
- let key_str = key.into();
394
-
395
- let container = if let Some(container) = self.config.di_container.take() {
396
- Arc::try_unwrap(container).unwrap_or_else(|_arc| DependencyContainer::new())
397
- } else {
398
- DependencyContainer::new()
399
- };
400
-
401
- let mut container = container;
402
-
403
- let dep = ValueDependency::new(key_str.clone(), value);
404
-
405
- container
406
- .register(key_str, Arc::new(dep))
407
- .expect("Failed to register dependency");
408
-
409
- self.config.di_container = Some(Arc::new(container));
410
- self
411
- }
412
-
413
- /// Register a factory dependency (like Litestar Provide)
414
- ///
415
- /// Factory dependencies create values on-demand, optionally depending on other
416
- /// registered dependencies. Factories are async and have access to resolved dependencies.
417
- ///
418
- /// # Type Parameters
419
- ///
420
- /// * `F` - Factory function type
421
- /// * `Fut` - Future returned by the factory
422
- /// * `T` - Type of value produced by the factory
423
- ///
424
- /// # Arguments
425
- ///
426
- /// * `key` - Unique identifier for this dependency
427
- /// * `factory` - Async function that creates the dependency value
428
- ///
429
- /// # Example
430
- ///
431
- /// ```ignorerust
432
- /// # #[cfg(feature = "di")]
433
- /// # {
434
- /// use spikard_http::ServerConfig;
435
- /// use std::sync::Arc;
436
- ///
437
- /// let config = ServerConfig::builder()
438
- /// .provide_value("db_url", "postgresql://localhost/mydb".to_string())
439
- /// .provide_factory("db_pool", |resolved| async move {
440
- /// let url: Arc<String> = resolved.get("db_url").ok_or("Missing db_url")?;
441
- /// // Create database pool...
442
- /// Ok(format!("Pool: {}", url))
443
- /// })
444
- /// .build();
445
- /// # }
446
- /// ```
447
- #[cfg(feature = "di")]
448
- pub fn provide_factory<F, Fut, T>(mut self, key: impl Into<String>, factory: F) -> Self
449
- where
450
- F: Fn(&spikard_core::di::ResolvedDependencies) -> Fut + Send + Sync + Clone + 'static,
451
- Fut: std::future::Future<Output = Result<T, String>> + Send + 'static,
452
- T: Send + Sync + 'static,
453
- {
454
- use futures::future::BoxFuture;
455
- use spikard_core::di::{DependencyContainer, DependencyError, FactoryDependency};
456
- use std::sync::Arc;
457
-
458
- let key_str = key.into();
459
-
460
- let container = if let Some(container) = self.config.di_container.take() {
461
- Arc::try_unwrap(container).unwrap_or_else(|_| DependencyContainer::new())
462
- } else {
463
- DependencyContainer::new()
464
- };
465
-
466
- let mut container = container;
467
-
468
- let factory_clone = factory.clone();
469
-
470
- let dep = FactoryDependency::builder(key_str.clone())
471
- .factory(
472
- move |_req: &axum::http::Request<()>,
473
- _data: &spikard_core::RequestData,
474
- resolved: &spikard_core::di::ResolvedDependencies| {
475
- let factory = factory_clone.clone();
476
- let factory_result = factory(resolved);
477
- Box::pin(async move {
478
- let result = factory_result
479
- .await
480
- .map_err(|e| DependencyError::ResolutionFailed { message: e })?;
481
- Ok(Arc::new(result) as Arc<dyn std::any::Any + Send + Sync>)
482
- })
483
- as BoxFuture<'static, Result<Arc<dyn std::any::Any + Send + Sync>, DependencyError>>
484
- },
485
- )
486
- .build()
487
- .expect("Factory dependency must have a configured factory function");
488
-
489
- container
490
- .register(key_str, Arc::new(dep))
491
- .expect("Failed to register dependency");
492
-
493
- self.config.di_container = Some(Arc::new(container));
494
- self
495
- }
496
-
497
- /// Register a dependency with full control (advanced API)
498
- ///
499
- /// This method allows you to register custom dependency implementations
500
- /// that implement the `Dependency` trait. Use this for advanced use cases
501
- /// where you need fine-grained control over dependency resolution.
502
- ///
503
- /// # Example
504
- ///
505
- /// ```ignorerust
506
- /// # #[cfg(feature = "di")]
507
- /// # {
508
- /// use spikard_http::ServerConfig;
509
- /// use spikard_core::di::ValueDependency;
510
- /// use std::sync::Arc;
511
- ///
512
- /// let dep = ValueDependency::new("custom", "value".to_string());
513
- ///
514
- /// let config = ServerConfig::builder()
515
- /// .provide(Arc::new(dep))
516
- /// .build();
517
- /// # }
518
- /// ```
519
- #[cfg(feature = "di")]
520
- pub fn provide(mut self, dependency: std::sync::Arc<dyn spikard_core::di::Dependency>) -> Self {
521
- use spikard_core::di::DependencyContainer;
522
- use std::sync::Arc;
523
-
524
- let key = dependency.key().to_string();
525
-
526
- let container = if let Some(container) = self.config.di_container.take() {
527
- Arc::try_unwrap(container).unwrap_or_else(|_| DependencyContainer::new())
528
- } else {
529
- DependencyContainer::new()
530
- };
531
-
532
- let mut container = container;
533
-
534
- container
535
- .register(key, dependency)
536
- .expect("Failed to register dependency");
537
-
538
- self.config.di_container = Some(Arc::new(container));
539
- self
540
- }
541
-
542
- /// Build the ServerConfig
543
- pub fn build(self) -> ServerConfig {
544
- self.config
545
- }
546
- }
547
-
548
- /// Build a Tokio runtime for serving HTTP requests with the configured worker count.
549
- ///
550
- /// `workers == 1` uses a current-thread runtime to minimize scheduling overhead.
551
- /// `workers > 1` uses a multi-thread runtime with an explicit worker thread count.
552
- pub fn build_server_runtime(config: &ServerConfig) -> std::io::Result<Runtime> {
553
- let mut builder = if config.workers <= 1 {
554
- tokio::runtime::Builder::new_current_thread()
555
- } else {
556
- let mut builder = tokio::runtime::Builder::new_multi_thread();
557
- builder.worker_threads(config.workers);
558
- builder
559
- };
560
-
561
- builder.enable_all().build()
562
- }
563
-
564
- const fn default_true() -> bool {
565
- true
566
- }