ktor-documentation icon indicating copy to clipboard operation
ktor-documentation copied to clipboard

Add reverse routing (link building) docs and tests

Open cies opened this issue 1 year ago • 0 comments

This adds documentation and tests for generating links based on resources.

I did not find adequate docs for this, once I did find the methods I wanted to know how to use them exactly. Instead of trying it on an example project of my own, I decided to extend an existing example that is part of this repo and add a section to the documentation to improve visibility for this feature to those who may be looking for the same.

In this issue I have also commented on the lack of documentation in this area, which this PR should solve.


Side-track remark to whom ever may be interested:

While the resource based routes specification is solid and very type safe wrt parameter types, it is also very verbose and add lots of indirection for simple routing needs. In other frameworks (mainly RoR and Play1) the router basically couples a path (possible with path params) to a controller action method, and allows one to build the path (or full url) from a reference to a controller action method. This is much simpler conceptually than having the routes defined separately as resources, and using those resources to configure the router and to build links.

Ktor also seems to lack the concept of Controllers, which is probably pretty simple to add (as some have tried). But say some controller system exists, I would like to do the following:

// define routes that link path specifications directly to controller action methods
get("/" to intern.ui.Application::index)
post("/api/documents" to intern.api.Attachments::add)
post("/api/documents/{id}/delete" to intern.api.Attachments::delete)

// build links by using the controller action method references as selectors
val link1 = href(intern.ui.Application::index) // => "/"
val link2 = href(intern.api.Attachments::delete, mapOf("id" to 123)) // => "/api/documents/123/delete"

instead of this very verbose solution that is currently the way to go with Ktor:

@Serializable
@Resource("/articles")
class Articles(val sort: String? = "new") {
    @Serializable
    @Resource("new")
    class New(val parent: Articles = Articles(sort = null))

    @Serializable
    @Resource("{id}")
    class Id(val parent: Articles = Articles(), val id: Long) {
        @Serializable
        @Resource("edit")
        class Edit(val parent: Id)
    }
}

// routing
get<Articles> { route -> ... }
get<Articles.New> { route -> ... }
post<Articles> { route -> ... }

// link building
val urlBuilder = URLBuilder(host = "ktor.io", parameters = parametersOf("token", "123"))
href(Articles(sort = null), urlBuilder)
val link = urlBuilder.buildString()

Long story short. We're evaluating Ktor and find that the routing/link-building is quite verbose compared to what we've grown accustomed to.

cies avatar Jul 31 '22 12:07 cies