Handling requests
Ktor allows you to handle incoming requests and send responses inside route handlers.
Route handlers operate on an ApplicationCall, which represents a single HTTP exchange between the client and the server. It is available in route handlers through the call property and contains both the incoming request (ApplicationRequest) and the outgoing response (ApplicationResponse).
Within a route handler, you can use the ApplicationCall to:
Access request information, such as headers, cookies, and connection details.
Retrieve path parameter values.
Retrieve query parameters.
Receive request body content, such as data objects, form parameters, and files.
General request information
You can access request data through the call.request property. This returns an ApplicationRequest instance, which provides access to low-level HTTP request information.
For example, you can retrieve the request URI in a GET request handler using call.request.uri:
The call.respondText() function sends a plain text response back to the client.
Headers
To access all HTTP request headers, use the ApplicationRequest.headers property.
For convenience, Ktor also provides dedicated extension functions for accessing commonly used headers, such as .acceptEncoding(), .contentType(), and .cacheControl().
Cookies
To access the cookies sent with the request, use the ApplicationRequest.cookies property.
Connection details
Use the ApplicationRequest.local property to get access to connection details such as a host name, port, and scheme.
X-Forwarded- headers
To obtain information about a request passed through an HTTP proxy or a load balancer, install the Forwarded headers plugin and use the ApplicationRequest.origin property.
Path parameters
When handling requests, you can retrieve path parameter values using the ApplicationCall.parameters property.
For example, in the code snippet below, call.parameters["login"] returns "admin" for the /user/admin path:
Query parameters
To retrieve parameters of a URL query string, you can use the ApplicationRequest.queryParameters property.
The following example accesses the price query parameter from a request made to /products?price=asc:
You can also get the entire query string using the ApplicationRequest.queryString() function.
Required request parameters
When handling requests, it is common to extract values from path parameters, query parameters, headers, or cookies and validate that they are present before continuing request processing.
Instead of manually checking for missing values in every route handler, Ktor provides the following helper functions that simplify accessing required request data:
ApplicationCall.requireQueryParameter()— retrieves a required query parameter from the request URL. Throws if the parameter is missing.ApplicationCall.requireHeader()— retrieves a required HTTP header value. Throws if the header is not present in the request.ApplicationCall.requireCookie()— retrieves a required cookie value, optionally decoding it using the specified encoding. Throws if the cookie is missing.RoutingCall.requirePathParameter()— retrieves a required path parameter from the route definition. Throws if the parameter is not present in the matched route.
Each function returns a non-null value or throws MissingRequestParameterException if the value is missing.
Body contents
This section shows how to receive body contents sent with POST, PUT, or PATCH.
Raw payload
To access the raw body payload and parse it manually, use the ApplicationCall.receive() function that accepts a type of payload to be received. Suppose you have the following HTTP request:
You can receive the body of this request as an object of the specified type in one of the following ways:
String
To receive a request body as a String value, use
call.receive<String>(). You can also use.receiveText()to achieve the same result:post("/text") { val text = call.receiveText() call.respondText(text) }ByteArray
To receive the body of a request as a byte array, call
call.receive<ByteArray>():post("/bytes") { val bytes = call.receive<ByteArray>() call.respond(String(bytes)) }ByteReadChannel
You can use
call.receive<ByteReadChannel>()or.receiveChannel()to receiveByteReadChannelthat enables asynchronous reading of byte sequences:post("/channel") { val readChannel = call.receiveChannel() val text = readChannel.readRemaining().readString() call.respondText(text) }The sample below shows how to use
ByteReadChannelto upload a file:post("/upload") { val file = File("uploads/ktor_logo.png") call.receiveChannel().copyAndClose(file.writeChannel()) call.respondText("A file is uploaded") }
Objects
Ktor provides a ContentNegotiation plugin to negotiate the media type of request and deserialize content to an object of a required type.
To receive and convert content for a request, call the ApplicationCall.receive() function that accepts a data class as a parameter:
Form parameters
Ktor allows you to receive form parameters sent with both x-www-form-urlencoded and multipart/form-data types using the receiveParameters function. The example below shows an HTTP client POST request with form parameters passed in a body:
You can obtain parameter values in code as follows:
Multipart form data
To receive a file sent as a part of a multipart request, call the .receiveMultipart() function and then loop over each part as required.
Multipart request data is processed sequentially, so you can't directly access a specific part of it. Additionally, these requests can contain different types of parts, such as form fields, files, or binary data, which need to be handled differently.
The example demonstrates how to receive a file and save it to a file system:
Default file size limit
By default, the allowed size for binary and file items that can be received is limited to 50MiB. If a received file or binary item exceeds the 50MiB limit, an IOException is thrown.
To override the default form field limit, pass the formFieldLimit parameter when calling .receiveMultipart():
In this example, the new limit is set to 100MiB.
Form fields
PartData.FormItem represents a form field, which values can be accessed through the value property:
File uploads
PartData.FileItem represents a file item. You can handle file uploads as byte streams:
The .provider() function returns a ByteReadChannel, which allows you to read data incrementally. Using the .copyAndClose() function, you then write the file content to the specified destination while ensuring proper resource cleanup.
To determine the uploaded file size, you can get the Content-Length header value inside the post handler:
Resource cleanup
Once the form processing is complete, each part is disposed of using the .dispose() function to free resources.