@@ -8,78 +8,62 @@ import io.ktor.server.netty.Netty
88import io.ktor.server.plugins.BadRequestException
99import io.ktor.server.plugins.contentnegotiation.*
1010import io.ktor.server.plugins.openapi.*
11- import io.ktor.server.plugins.statuspages.* // Added import for StatusPages
11+ import io.ktor.server.plugins.statuspages.*
1212import io.ktor.server.plugins.swagger.*
1313import io.ktor.server.request.*
1414import io.ktor.server.response.*
1515import io.ktor.server.routing.*
1616import java.util.concurrent.ConcurrentHashMap
1717import kotlin.random.Random
1818import kotlinx.serialization.Serializable
19- import kotlinx.serialization.SerializationException // Added import for SerializationException
19+ import kotlinx.serialization.SerializationException
2020import kotlinx.serialization.json.Json
2121
22- // Define globalErrorRate at the top level
23- var globalErrorRate: Double = 0.1 // Default value, can be overridden in tests
22+ var globalErrorRate: Double = 0.1
2423
2524@Serializable data class Quote (val id : String? = null , val text : String , val author : String )
2625
2726fun main () {
28- // You might want to set globalErrorRate from command-line args here if needed for
29- // standalone runs
30- // For example, by parsing args or environment variables.
31- // This example focuses on test override, so we leave it as is for main.
3227 embeddedServer(Netty , port = 8080 , module = Application ::module).start(wait = true )
3328}
3429
3530fun Application.module () {
3631 log.info(" Using global error rate: $globalErrorRate " )
3732
38- // Conditionally install StatusPages to prevent DuplicatePluginException
39- if (pluginOrNull(StatusPages ) == null ) {
40- install(StatusPages ) {
41- exception<BadRequestException > { call, cause ->
42- call.application.log.warn(" Bad request for ${call.request.path()} : ${cause.message} " )
43- call.respond(
44- HttpStatusCode .BadRequest ,
45- mapOf (
46- " error" to " BAD_REQUEST" ,
47- " message" to (cause.message ? : " Invalid or missing request body." )
48- )
49- )
50- }
51- exception<SerializationException > { call, cause ->
52- call.application.log.warn(
53- " Request deserialization failed for ${call.request.path()} : ${cause.message} "
54- )
55- call.respond(
56- HttpStatusCode .BadRequest ,
57- mapOf (
58- " error" to " DESERIALIZATION_ERROR" ,
59- " message" to (cause.message ? : " Invalid request format or missing fields." )
60- )
61- )
62- }
33+ install(StatusPages ) {
34+ exception<BadRequestException > { call, cause ->
35+ call.application.log.warn(" Bad request for ${call.request.path()} : ${cause.message} " )
36+ call.respond(
37+ HttpStatusCode .BadRequest ,
38+ mapOf (
39+ " error" to " BAD_REQUEST" ,
40+ " message" to (cause.message ? : " Invalid or missing request body." )
41+ )
42+ )
6343 }
64- } else {
65- // Optional: Log or handle the case where StatusPages is already installed,
66- // potentially by the test harness. We might need to ensure our specific
67- // handlers are added/merged if the test harness installs a default one.
68- log.debug(" StatusPages plugin already installed. Skipping re-installation by module." )
69- }
70-
71- // Conditionally install ContentNegotiation to prevent DuplicatePluginException
72- if (pluginOrNull(ContentNegotiation ) == null ) {
73- install(ContentNegotiation ) {
74- json(
75- Json {
76- prettyPrint = true
77- isLenient = true
78- }
44+ exception<SerializationException > { call, cause ->
45+ call.application.log.warn(
46+ " Request deserialization failed for ${call.request.path()} : ${cause.message} "
47+ )
48+ call.respond(
49+ HttpStatusCode .BadRequest ,
50+ mapOf (
51+ " error" to " DESERIALIZATION_ERROR" ,
52+ " message" to (cause.message ? : " Invalid request format or missing fields." )
53+ )
7954 )
8055 }
8156 }
8257
58+ install(ContentNegotiation ) {
59+ json(
60+ Json {
61+ prettyPrint = true
62+ isLenient = true
63+ }
64+ )
65+ }
66+
8367 val quotes =
8468 ConcurrentHashMap <String , Quote >().apply {
8569 put(
@@ -127,7 +111,7 @@ fun Application.module() {
127111 routing {
128112 route(" /api/quotes" ) {
129113 get {
130- if (Random .nextDouble() < globalErrorRate) { // Use globalErrorRate
114+ if (Random .nextDouble() < globalErrorRate) {
131115 call.respond(
132116 HttpStatusCode .InternalServerError ,
133117 " Simulated error for observability testing"
@@ -138,7 +122,7 @@ fun Application.module() {
138122 }
139123
140124 post {
141- if (Random .nextDouble() < globalErrorRate) { // Use globalErrorRate
125+ if (Random .nextDouble() < globalErrorRate) {
142126 call.respond(
143127 HttpStatusCode .InternalServerError ,
144128 " Simulated error for observability testing"
@@ -172,14 +156,13 @@ fun Application.module() {
172156 }
173157 quotes[newId] = newQuote
174158
175- // Log the quote that will actually be sent in the response
176159 application.log.info(" Responding with: $newQuote " )
177160 call.respond(HttpStatusCode .Created , newQuote)
178161 }
179162 }
180163
181164 get(" /api/quotes/{id}" ) {
182- if (Random .nextDouble() < globalErrorRate) { // Use globalErrorRate
165+ if (Random .nextDouble() < globalErrorRate) {
183166 call.respond(
184167 HttpStatusCode .InternalServerError ,
185168 " Simulated error for observability testing"
@@ -188,24 +171,22 @@ fun Application.module() {
188171 }
189172 val id =
190173 call.parameters[" id" ]
191- ? : return @get call.respond( // Changed to respond with JSON
174+ ? : return @get call.respond(
192175 HttpStatusCode .BadRequest ,
193176 mapOf (" error" to " MISSING_ID" , " message" to " Missing ID" )
194177 )
195178 val quote =
196179 quotes[id]
197- ? : return @get call.respond( // Changed to respond with JSON
180+ ? : return @get call.respond(
198181 HttpStatusCode .NotFound ,
199182 mapOf (" error" to " NOT_FOUND" , " message" to " Quote not found" )
200183 )
201184 call.respond(quote)
202185 }
203186
204- // Add OpenAPI and Swagger support
205187 openAPI(path = " openapi" )
206188 swaggerUI(path = " swagger" )
207189
208- // Liveness and Readiness endpoint
209190 route(" /internal" ) {
210191 get(" /health" ) { call.respond(HttpStatusCode .OK , " Application is healthy" ) }
211192 }
0 commit comments