Skip to content

Commit f3bd768

Browse files
committed
Refine Ktor-style routing DSL examples and tests
1 parent b3bfed8 commit f3bd768

8 files changed

Lines changed: 164 additions & 114 deletions

File tree

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
import com.google.gson.JsonObject
2-
import io.netty.handler.codec.http.FullHttpResponse
32
import net.ccbluex.netty.http.HttpServer
4-
import net.ccbluex.netty.http.model.RequestObject
5-
import net.ccbluex.netty.http.util.httpOk
3+
import net.ccbluex.netty.http.routing.Routing
4+
import net.ccbluex.netty.http.routing.RoutingContext
65

76
suspend fun main() {
87
val server = HttpServer()
98

109
server.routing {
11-
post("/echo", ::postEcho) // /echo
10+
echoRoutes()
1211
}
1312

1413
server.start(8080) // Start the server on port 8080
1514
}
1615

17-
fun postEcho(requestObject: RequestObject): FullHttpResponse {
18-
return httpOk(requestObject.asJson<JsonObject>())
19-
}
16+
fun Routing.echoRoutes() {
17+
route("/echo") {
18+
post { postEcho() }
19+
}
20+
}
21+
22+
private suspend fun RoutingContext.postEcho() {
23+
respond(receive<JsonObject>())
24+
}
Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import com.google.gson.JsonObject
2-
import io.netty.handler.codec.http.FullHttpResponse
32
import net.ccbluex.netty.http.HttpServer
4-
import net.ccbluex.netty.http.model.RequestObject
5-
import net.ccbluex.netty.http.util.httpBadRequest
6-
import net.ccbluex.netty.http.util.httpOk
3+
import net.ccbluex.netty.http.routing.Routing
4+
import net.ccbluex.netty.http.routing.RoutingContext
75
import java.io.File
86

97
const val FOLDER_NAME = "files"
@@ -15,11 +13,7 @@ suspend fun main() {
1513
println("Serving files from: ${folder.absolutePath}")
1614

1715
server.routing {
18-
get("/", ::getRoot)
19-
get("/conflicting", ::getConflictingPath)
20-
get("/a/b/c", ::getConflictingPath)
21-
get("/file/:name", ::getFileInformation)
22-
post("/file/:name", ::postFile)
16+
fileRoutes()
2317

2418
// register file serving at the bottom of the routing tree
2519
// to avoid overwriting other routes
@@ -29,50 +23,60 @@ suspend fun main() {
2923
server.start(8080) // Start the server on port 8080
3024
}
3125

32-
@Suppress("UNUSED_PARAMETER")
33-
fun getRoot(requestObject: RequestObject): FullHttpResponse {
34-
// Count the number of files in the folder
35-
// Walk the folder and count the number of files
36-
return httpOk(JsonObject().apply {
26+
fun Routing.fileRoutes() {
27+
get("/") { getRoot() }
28+
get("/conflicting") { getConflictingPath() }
29+
30+
route("/a") {
31+
route("/b") {
32+
get("/c") { getConflictingPath() }
33+
}
34+
}
35+
36+
route("/file") {
37+
get("/:name") { getFileInformation() }
38+
post("/:name") { postFile() }
39+
}
40+
}
41+
42+
private suspend fun RoutingContext.getRoot() {
43+
respond(JsonObject().apply {
3744
addProperty("path", folder.absolutePath)
3845
addProperty("files", folder.walk().count())
3946
})
4047
}
4148

42-
@Suppress("UNUSED_PARAMETER")
43-
fun getConflictingPath(requestObject: RequestObject): FullHttpResponse {
44-
return httpOk(JsonObject().apply {
49+
private suspend fun RoutingContext.getConflictingPath() {
50+
respond(JsonObject().apply {
4551
addProperty("message", "This is a conflicting path")
4652
})
4753
}
4854

49-
@Suppress("UNUSED_PARAMETER")
50-
fun getFileInformation(requestObject: RequestObject): FullHttpResponse {
51-
val name = requestObject.params["name"] ?: return httpBadRequest("Missing name parameter")
55+
private suspend fun RoutingContext.getFileInformation() {
56+
val name = parameters["name"] ?: badRequest("Missing name parameter")
5257
val file = File(folder, name)
5358

5459
if (!file.exists()) {
55-
return httpBadRequest("File not found")
60+
badRequest("File not found")
5661
}
5762

58-
return httpOk(JsonObject().apply {
63+
respond(JsonObject().apply {
5964
addProperty("name", file.name)
6065
addProperty("size", file.length())
6166
addProperty("lastModified", file.lastModified())
6267
})
6368
}
6469

65-
@Suppress("UNUSED_PARAMETER")
66-
fun postFile(requestObject: RequestObject): FullHttpResponse {
67-
val name = requestObject.params["name"] ?: return httpBadRequest("Missing name parameter")
70+
private suspend fun RoutingContext.postFile() {
71+
val name = parameters["name"] ?: badRequest("Missing name parameter")
6872
val file = File(folder, name)
6973

7074
if (file.exists()) {
71-
return httpBadRequest("File already exists")
75+
badRequest("File already exists")
7276
}
7377

74-
file.writeText(requestObject.body)
75-
return httpOk(JsonObject().apply {
78+
file.writeText(body)
79+
respond(JsonObject().apply {
7680
addProperty("message", "File written")
7781
})
78-
}
82+
}

examples/hello-world/src/main/kotlin/HelloWorldExample.kt

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
import com.google.gson.JsonObject
2-
import io.netty.handler.codec.http.FullHttpResponse
32
import net.ccbluex.netty.http.HttpServer
4-
import net.ccbluex.netty.http.model.RequestObject
5-
import net.ccbluex.netty.http.util.httpOk
3+
import net.ccbluex.netty.http.routing.Routing
4+
import net.ccbluex.netty.http.routing.RoutingContext
65

76
suspend fun main() {
87
val server = HttpServer()
98

109
server.routing {
11-
get("/", ::getRoot)
12-
get("/hello", ::getHello) // /hello?name=World
13-
get("/hello/:name", ::getHello) // /hello/World
14-
get("/hello/:name/:age", ::getHelloWithAge) // /hello/World/20
10+
helloWorldRoutes()
1511
}
1612

1713
server.start(8080) // Start the server on port 8080
1814
}
1915

20-
@Suppress("UNUSED_PARAMETER")
21-
fun getRoot(requestObject: RequestObject): FullHttpResponse {
22-
return httpOk(JsonObject().apply {
16+
fun Routing.helloWorldRoutes() {
17+
get("/") { getRoot() }
18+
19+
route("/hello") {
20+
get { getHello() } // /hello?name=World
21+
get("/:name") { getHello() } // /hello/World
22+
get("/:name/:age") { getHelloWithAge() } // /hello/World/20
23+
}
24+
}
25+
26+
private suspend fun RoutingContext.getRoot() {
27+
respond(JsonObject().apply {
2328
addProperty("root", true)
2429
})
2530
}
2631

27-
fun getHello(requestObject: RequestObject): FullHttpResponse {
28-
val name = requestObject.params["name"] ?: requestObject.queryParams["name"] ?: "World"
29-
return httpOk(JsonObject().apply {
32+
private suspend fun RoutingContext.getHello() {
33+
val name = parameters["name"] ?: queryParameters["name"] ?: "World"
34+
respond(JsonObject().apply {
3035
addProperty("message", "Hello, $name!")
3136
})
3237
}
3338

34-
fun getHelloWithAge(requestObject: RequestObject): FullHttpResponse {
35-
val name = requestObject.params["name"] ?: "World"
36-
val age = requestObject.params["age"] ?: "0"
37-
return httpOk(JsonObject().apply {
39+
private suspend fun RoutingContext.getHelloWithAge() {
40+
val name = parameters["name"] ?: "World"
41+
val age = parameters["age"] ?: "0"
42+
respond(JsonObject().apply {
3843
addProperty("message", "Hello, $name! You are $age years old.")
3944
})
4045
}
41-

examples/zip-server/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ dependencies {
2323
}
2424

2525
application {
26-
mainClass.set("HelloWorldExampleKt")
26+
mainClass.set("ZipServerExampleKt")
2727
}
2828

2929
tasks.test {
@@ -36,11 +36,11 @@ tasks.withType<JavaCompile> {
3636

3737
tasks.withType<Jar> {
3838
manifest {
39-
attributes["Main-Class"] = "HelloWorldExampleKt"
39+
attributes["Main-Class"] = "ZipServerExampleKt"
4040
}
4141

4242
// Include runtime dependencies in the JAR
4343
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
4444
// Prevent duplicate files from being added to the JAR
4545
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
46-
}
46+
}

examples/zip-server/src/main/kotlin/ZipServerExample.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@
1919
*/
2020

2121
import net.ccbluex.netty.http.HttpServer
22-
import net.ccbluex.netty.http.rest.RouteController
22+
import net.ccbluex.netty.http.routing.Routing
2323
import java.io.File
2424

2525
suspend fun main() {
2626
// Start server
2727
val server = HttpServer()
2828
server.routing {
29-
zip("/static", File("example.zip").inputStream())
29+
zipRoutes()
3030
}
3131

3232
server.start(8080)
3333
}
34+
35+
fun Routing.zipRoutes() {
36+
zip("/static", File("example.zip").inputStream())
37+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package net.ccbluex.netty.http.routing
2+
3+
import net.ccbluex.netty.http.rest.Node
4+
5+
typealias Routing = Node

src/test/kotlin/HttpMiddlewareServerTest.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import com.google.gson.JsonObject
2-
import io.netty.handler.codec.http.FullHttpResponse
32
import io.netty.handler.codec.http.HttpResponseStatus
43
import kotlinx.coroutines.runBlocking
54
import net.ccbluex.netty.http.HttpServer
65
import net.ccbluex.netty.http.middleware.Middleware
7-
import net.ccbluex.netty.http.model.RequestObject
6+
import net.ccbluex.netty.http.routing.Routing
7+
import net.ccbluex.netty.http.routing.RoutingContext
88
import net.ccbluex.netty.http.util.httpBadRequest
9-
import net.ccbluex.netty.http.util.httpOk
109
import okhttp3.OkHttpClient
1110
import okhttp3.Request
1211
import okhttp3.Response
@@ -63,7 +62,7 @@ class HttpMiddlewareServerTest {
6362
val server = HttpServer()
6463

6564
server.routing {
66-
get("/", ::static)
65+
middlewareRoutes()
6766
}
6867

6968
server.middleware(Middleware.OnResponse { requestContext, fullHttpResponse ->
@@ -85,13 +84,16 @@ class HttpMiddlewareServerTest {
8584
server
8685
}
8786

88-
@Suppress("UNUSED_PARAMETER")
89-
fun static(requestObject: RequestObject): FullHttpResponse {
90-
return httpOk(JsonObject().apply {
87+
private suspend fun RoutingContext.static() {
88+
respond(JsonObject().apply {
9189
addProperty("message", "Hello, World!")
9290
})
9391
}
9492

93+
private fun Routing.middlewareRoutes() {
94+
get("/") { static() }
95+
}
96+
9597
/**
9698
* Utility function to make HTTP GET requests to the specified path.
9799
*

0 commit comments

Comments
 (0)