Skip to content

Commit 13f9af7

Browse files
WD-321 Make default configurations rewritable (#15)
* WD-321 Make default configurations rewritable * WD-321 Fix sample * WD-321 Fix filter API configuration * WD-321 Fix version, small fixes * WD-321 Fix version, small fixes * WD-321 change configuration API to apply struct Co-authored-by: Alex Shvedov <alexeii.shvedov@gmail.com>
1 parent 5f585be commit 13f9af7

File tree

6 files changed

+83
-76
lines changed

6 files changed

+83
-76
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ repositories {
1212
}
1313

1414
// Append dependency
15-
implementation("com.icerockdev:web-utils:0.3.1")
15+
implementation("com.icerockdev:web-utils:0.4.0")
1616
````
1717

1818
## Library usage

sample/src/main/kotlin/com/icerockdev/sample/server.kt

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package com.icerockdev.sample
66

7+
import com.fasterxml.jackson.databind.SerializationFeature
78
import com.icerockdev.api.AbstractResponse
89
import com.icerockdev.api.Request
910
import com.icerockdev.exception.ForbiddenException
@@ -12,9 +13,9 @@ import com.icerockdev.exception.ValidationException
1213
import com.icerockdev.util.QueryParser
1314
import com.icerockdev.util.receiveQuery
1415
import com.icerockdev.webserver.*
15-
import com.icerockdev.webserver.log.LoggingConfiguration
1616
import com.icerockdev.webserver.log.JsonDataLogger
1717
import com.icerockdev.webserver.log.JsonSecret
18+
import com.icerockdev.webserver.log.LoggingConfiguration
1819
import com.icerockdev.webserver.log.jsonLogger
1920
import com.icerockdev.webserver.tools.receiveRequest
2021
import io.ktor.application.Application
@@ -31,26 +32,43 @@ import io.ktor.util.KtorExperimentalAPI
3132

3233
@KtorExperimentalAPI
3334
fun Application.main() {
34-
install(StatusPages, getStatusConfiguration())
35+
install(StatusPages) {
36+
applyStatusConfiguration()
37+
}
38+
3539
install(CORS) {
3640
applyDefaultCORS()
3741
anyHost() // @TODO: Don't do this in production if possible. Try to limit it.
3842
}
3943
install(DefaultHeaders)
4044
install(CallLogging) {
4145
applyDefaultLogging()
46+
// Log only /api requests
47+
// filter { call -> call.request.path().startsWith("/api") }
4248
}
4349
install(JsonDataLogger) {
44-
mapperConfiguration = getObjectMapper()
50+
mapperConfiguration = {
51+
applyObjectMapper()
52+
}
4553
loggingConfiguration =
46-
LoggingConfiguration(responseTypes = listOf(AbstractResponse::class, CustomResponse::class))
54+
LoggingConfiguration(
55+
responseTypes = listOf(AbstractResponse::class, CustomResponse::class),
56+
requestTypes = listOf(Request::class)
57+
)
58+
}
59+
install(CallId) {
60+
applyCallConfiguration()
4761
}
48-
install(CallId, getCallConfiguration())
4962
install(ContentNegotiation) {
50-
jackson(block = getObjectMapper())
63+
jackson() {
64+
applyObjectMapper()
65+
configure(SerializationFeature.INDENT_OUTPUT, false)
66+
}
5167
}
5268
install(QueryParser) {
53-
mapperConfiguration = getObjectMapper()
69+
mapperConfiguration = {
70+
applyObjectMapper()
71+
}
5472
}
5573

5674
/**

web-utils/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ apply(plugin = "java")
1313
apply(plugin = "kotlin")
1414

1515
group = "com.icerockdev"
16-
version = "0.3.1"
16+
version = "0.4.0"
1717

1818
val sourcesJar by tasks.registering(Jar::class) {
1919
classifier = "sources"

web-utils/src/main/kotlin/com/icerockdev/webserver/configuration.kt

Lines changed: 48 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -28,50 +28,47 @@ import org.slf4j.LoggerFactory
2828
import org.slf4j.event.Level
2929
import java.util.*
3030

31-
fun getStatusConfiguration(): StatusPages.Configuration.() -> Unit {
32-
33-
return {
34-
status(HttpStatusCode.NotFound) { status ->
35-
val error = ErrorResponse().also {
36-
it.status = status.value
37-
it.message = "Route not found"
38-
}
39-
call.respond(
40-
status,
41-
error
42-
)
31+
fun StatusPages.Configuration.applyStatusConfiguration() {
32+
status(HttpStatusCode.NotFound) { status ->
33+
val error = ErrorResponse().also {
34+
it.status = status.value
35+
it.message = "Route not found"
4336
}
44-
status(HttpStatusCode.Unauthorized) { status ->
45-
val error = ErrorResponse().also {
46-
it.status = status.value
47-
it.message = "Unauthorized"
48-
it.success = false
49-
}
50-
call.respond(
51-
status,
52-
error
53-
)
54-
}
55-
exception<UserException> { cause ->
56-
call.respond(
57-
HttpStatusCode(cause.status, cause.message.toString()),
58-
cause.getErrorResponse()
59-
)
37+
call.respond(
38+
status,
39+
error
40+
)
41+
}
42+
status(HttpStatusCode.Unauthorized) { status ->
43+
val error = ErrorResponse().also {
44+
it.status = status.value
45+
it.message = "Unauthorized"
46+
it.success = false
6047
}
61-
exception<Throwable> { cause ->
62-
val error = ErrorResponse().also {
63-
it.status = HttpStatusCode.InternalServerError.value
64-
it.message = cause.message.toString()
65-
}
66-
call.respond(
67-
HttpStatusCode.InternalServerError,
68-
error
69-
)
48+
call.respond(
49+
status,
50+
error
51+
)
52+
}
53+
exception<UserException> { cause ->
54+
call.respond(
55+
HttpStatusCode(cause.status, cause.message.toString()),
56+
cause.getErrorResponse()
57+
)
58+
}
59+
exception<Throwable> { cause ->
60+
val error = ErrorResponse().also {
61+
it.status = HttpStatusCode.InternalServerError.value
62+
it.message = cause.message.toString()
7063
}
64+
call.respond(
65+
HttpStatusCode.InternalServerError,
66+
error
67+
)
7168
}
7269
}
7370

74-
fun CORS.Configuration.applyDefaultCORS(): CORS.Configuration {
71+
fun CORS.Configuration.applyDefaultCORS() {
7572
method(HttpMethod.Options)
7673
method(HttpMethod.Put)
7774
method(HttpMethod.Delete)
@@ -81,10 +78,9 @@ fun CORS.Configuration.applyDefaultCORS(): CORS.Configuration {
8178
exposeHeader("X-Total-Count")
8279
allowCredentials = true
8380
allowNonSimpleContentTypes = true
84-
return this
8581
}
8682

87-
fun CallLogging.Configuration.applyDefaultLogging(): CallLogging.Configuration {
83+
fun CallLogging.Configuration.applyDefaultLogging() {
8884
level = Level.TRACE
8985
callIdMdc(Constants.LOG_FIELD_TRACE_UUID)
9086
mdc(Constants.LOG_FIELD_HEADERS) { call: ApplicationCall ->
@@ -99,27 +95,19 @@ fun CallLogging.Configuration.applyDefaultLogging(): CallLogging.Configuration {
9995
mdc(Constants.LOG_FIELD_REQUEST_PATH) { call: ApplicationCall ->
10096
call.request.path()
10197
}
102-
return this
103-
}
104-
105-
fun CallLogging.Configuration.applyApiFilter(): CallLogging.Configuration {
106-
filter { call -> call.request.path().startsWith("/api") }
107-
return this
10898
}
10999

110100
private fun entriesToString(entries: Set<Map.Entry<String, List<String>>>): String {
111101
return entries.joinToString(separator = "\n", transform = { String.format("%s: %s", it.key, it.value.first()) })
112102
}
113103

114104

115-
fun getObjectMapper(): ObjectMapper.() -> Unit {
116-
return {
117-
configure(SerializationFeature.INDENT_OUTPUT, true)
118-
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
119-
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
120-
dateFormat = StdDateFormat()
121-
registerKotlinModule()
122-
}
105+
fun ObjectMapper.applyObjectMapper() {
106+
configure(SerializationFeature.INDENT_OUTPUT, true)
107+
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
108+
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
109+
dateFormat = StdDateFormat()
110+
registerKotlinModule()
123111
}
124112

125113
fun getMonitoringPipeline(): suspend PipelineContext<Unit, ApplicationCall>.(Unit) -> Unit {
@@ -139,21 +127,19 @@ fun getMonitoringPipeline(): suspend PipelineContext<Unit, ApplicationCall>.(Uni
139127
} catch (e: Throwable) {
140128
call.respond(
141129
HttpStatusCode.InternalServerError,
142-
object : Response(
130+
Response(
143131
status = HttpStatusCode.InternalServerError.value,
144132
message = e.message ?: "",
145133
isSuccess = false
146-
) {}
134+
)
147135
)
148136
proceed()
149137
logger.error(e.localizedMessage, e)
150138
}
151139
}
152140
}
153141

154-
fun getCallConfiguration(): CallId.Configuration.() -> Unit {
155-
return {
156-
generate { UUID.randomUUID().toString() }
157-
header("X-Request-ID")
158-
}
159-
}
142+
fun CallId.Configuration.applyCallConfiguration() {
143+
generate { UUID.randomUUID().toString() }
144+
header("X-Request-ID")
145+
}

web-utils/src/main/kotlin/com/icerockdev/webserver/log/JsonDataLogger.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector
1616
import com.fasterxml.jackson.databind.jsontype.TypeSerializer
1717
import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer
1818
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
19+
import com.icerockdev.api.AbstractResponse
20+
import com.icerockdev.api.Request
1921
import com.icerockdev.webserver.Constants
2022
import com.icerockdev.webserver.Environment
2123
import io.ktor.application.*
@@ -45,7 +47,10 @@ class JsonDataLogger(configure: Configuration.() -> Unit) {
4547
var responseStatusCodeName: String = Constants.LOG_FIELD_STATUS_CODE
4648
var appEnvName: String = Constants.LOG_FIELD_ENV
4749
var systemEnvKey: String = "env"
48-
var loggingConfiguration: LoggingConfiguration = LoggingConfiguration()
50+
var loggingConfiguration: LoggingConfiguration = LoggingConfiguration(
51+
requestTypes = listOf(Request::class),
52+
responseTypes = listOf(AbstractResponse::class)
53+
)
4954
}
5055

5156
init {
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package com.icerockdev.webserver.log
22

3-
import com.icerockdev.api.AbstractResponse
4-
import com.icerockdev.api.Request
53
import kotlin.reflect.KClass
64

75
class LoggingConfiguration(
8-
val requestTypes: List<KClass<*>> = listOf(Request::class),
9-
val responseTypes: List<KClass<*>> = listOf(AbstractResponse::class)
6+
val requestTypes: List<KClass<*>>,
7+
val responseTypes: List<KClass<*>>
108
)

0 commit comments

Comments
 (0)