Utilities exposed by Ktor (URL-Encoding)

Handling URL-encoded properties

Ktor exposes a few extension methods for parsing and generating url-encoded strings (in the application/x-www-form-urlencoded mimetype format).

URL-encoded strings look like: param=value&other=hi.

Parsing:

There is an extension method for String that allows you to get a parsed Parameters object from it. You can limit the maximum number of parsed parameters with the optional limit parameter.

  1. fun String.parseUrlEncodedParameters(defaultEncoding: Charset = Charsets.UTF_8, limit: Int = 1000): Parameters

Encoding:

You can generate a URL-encoded string either from a List of Pairs of Strings or a Parameters instance:

  1. fun List<Pair<String, String?>>.formUrlEncode(): String
  2. fun List<Pair<String, String?>>.formUrlEncodeTo(out: Appendable)
  3. fun Parameters.formUrlEncode(): String
  4. fun Parameters.formUrlEncodeTo(out: Appendable)

You can construct a URL-encoded string from List<Pair<String, String>> like this:

  1. listOf(
  2. "error" to "invalid_request",
  3. "error_description" to "client_id is missing"
  4. ).formUrlEncode()

You can also construct it from a Parameters instance that you can instantiate by using the Parameters.build builder and then calling the formUrlEncode extension, or with the parametersOf() builder method:

  1. Parameters.build {
  2. append("error", "invalid_request")
  3. append("error_description", "client_id is missing")
  4. }.formUrlEncode()

The parametersOf builder has several signatures, and there is Parameters operator overloading (+) to join two Parameters instances:

  1. parametersOf("a" to "b1", "a" to "b2").formUrlEncode()
  2. (parametersOf("a", "b1") + parametersOf("a", "b2")).formUrlEncode()
  3. parametersOf("a", listOf("b1", "b2")).formUrlEncode()

From a normal Map<String, String> you can also construct a URL-encoded string, but first you will have to create a List from it:

  1. mapOf(
  2. "error" to "invalid_request",
  3. "error_description" to "client_id is missing"
  4. ).toList().formUrlEncode()

URL-encoded strings allow you to have repeated keys. If you use a Map<String, String> as base, you won’t be able to represent repeated keys.In this case consider using parametersOf, List or Parameters.build.

You can also construct it from a Map<String, List<String>> by flatMapping it first:

  1. mapOf(
  2. "error" to listOf("invalid_request"),
  3. "error_descriptions" to listOf("client_id is missing", "server error")
  4. ).flatMap { map -> map.value.map { map.key to it } }.formUrlEncode()

In case you want to avoid constructing a whole String with the content and instead want to write to somewhere directly, you can use the formUrlEncodeTo method.

Responding URL-encoded

You can do something like:

  1. call.respondUrlEncoded("hello" to listOf("world"))

by adding the following extension methods to your project:

  1. suspend fun ApplicationCall.respondUrlEncoded(vararg keys: Pair<String, List<String>>) =
  2. respondUrlEncoded(parametersOf(*keys))
  3. suspend fun ApplicationCall.respondUrlEncoded(parameters: Parameters) =
  4. respondTextWriter(ContentType.Application.FormUrlEncoded) {
  5. parameters.formUrlEncodeTo(this)
  6. }