Content conversion based on Content-Type and Accept headers

This feature provides automatic content conversion according to Content-Type and Accept headers.

This feature is defined in the class io.ktor.features.ContentNegotiation and no additional artifacts are required.

Basic Usage

The ContentNegotiation feature allows you to register and configure custom converters.

  1. install(ContentNegotiation) {
  2. register(MyContentType, MyContentTypeConverter()) {
  3. // Optionally configure the converter...
  4. }
  5. }

For example:

  1. install(ContentNegotiation) {
  2. register(ContentType.Application.Json, JacksonConverter())
  3. }

Sending

When you respond with an object that is not directly handled, like a custom data class,this feature checks the client’s Accept header to determine which Content-Type will be used and thus which ContentConverter will be called.

  1. call.respond(MyDataClass("hello", "world"))

Right now, the only supported ContentNegotiation strategy when sending, is theclient’s Accept header. There is an issue to implement other strategies.

Receiving

When receiving, the Content-Type of the request will be used to determinewhich ContentConverter will be used to process that request:

  1. val myDataClass = call.receive<MyDataClass>()

The ContentConverter interface

If you want to write your own converter, you have to implement the ContentConverter interface:

  1. interface ContentConverter {
  2. suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any?
  3. suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any?
  4. }

For example, the GsonConverter implementation looks like:

  1. class GsonConverter(private val gson: Gson = Gson()) : ContentConverter {
  2. override suspend fun convertForSend(context: PipelineContext<Any, ApplicationCall>, contentType: ContentType, value: Any): Any? {
  3. return TextContent(gson.toJson(value), contentType.withCharset(context.call.suitableCharset()))
  4. }
  5. override suspend fun convertForReceive(context: PipelineContext<ApplicationReceiveRequest, ApplicationCall>): Any? {
  6. val request = context.subject
  7. val channel = request.value as? ByteReadChannel ?: return null
  8. val reader = channel.readRemaining().readText((context.call.request.contentCharset() ?: Charsets.UTF_8).newDecoder()).reader()
  9. return gson.fromJson(reader, request.type.javaObjectType)
  10. }
  11. }

Available out of the box ContentConverter

Ktor provide some content converters out of the box: