Request validation
The RequestValidation plugin provides the ability to validate a body of incoming requests. You can validate a raw request body or specified request object properties if the ContentNegotiation
plugin with a serializer is installed. If a request body validation fails, the plugin raises RequestValidationException
, which can be handled using the StatusPages plugin.
Add dependencies
To use RequestValidation
, you need to include the ktor-server-request-validation
artifact in the build script:
Install RequestValidation
To install the RequestValidation
plugin to the application, pass it to the install
function in the specified module. The code snippets below show how to install RequestValidation
...
... inside the
embeddedServer
function call.... inside the explicitly defined
module
, which is an extension function of theApplication
class.
The RequestValidation
plugin can also be installed to specific routes. This might be useful if you need different RequestValidation
configurations for different application resources.
Configure RequestValidation
Configuring RequestValidation
involves three main steps:
1. Receive body
The RequestValidation
plugin validates a body of a request if you call the receive function with a type parameter. For instance, the code snippet below shows how to receive a body as a String
value:
2. Configure a validation function
To validate a request body, use the validate
function. This function returns a ValidationResult
object representing a successful or unsuccessful validation result. For an unsuccessful result, RequestValidationException is raised.
The validate
function has two overloads allowing you to validate a request body in two ways:
The first
validate
overload allows you to access a request body as the object of the specified type. The example below shows how to validate a request body representing aString
value:install(RequestValidation) { validate<String> { bodyText -> if (!bodyText.startsWith("Hello")) ValidationResult.Invalid("Body text should start with 'Hello'") else ValidationResult.Valid } }If you have the
ContentNegotiation
plugin installed configured with a specific serializer, you can validate object properties. Learn more from Example: Validating object properties.The second
validate
overload acceptsValidatorBuilder
and allows you to provide custom validation rules. You can learn more from Example: Validating byte arrays.
3. Handle validation exceptions
If request validation is failed, RequestValidation
raises RequestValidationException
. This exception allows you to access a request body and get reasons for all validation failures for this request.
You can handle RequestValidationException
using the StatusPages plugin as follows:
You can find the full example here: request-validation.
Example: Validating object properties
In this example, we'll look at how to validate object properties using the RequestValidation
plugin. Suppose the server receives a POST
request with the following JSON data:
To add validation of the id
property, follow the steps below:
Create the
Customer
data class that describes the JSON object above:@Serializable data class Customer(val id: Int, val firstName: String, val lastName: String)Install the
ContentNegotiation
plugin with the JSON serializer:install(ContentNegotiation) { json() }Receive the
Customer
object on the server side as follows:post("/json") { val customer = call.receive<Customer>() call.respond(customer) }In the
RequestValidation
plugin configuration, add validation of theid
property to make sure it falls into a specified range:install(RequestValidation) { validate<Customer> { customer -> if (customer.id <= 0) ValidationResult.Invalid("A customer ID should be greater than 0") else ValidationResult.Valid } }In this case,
RequestValidation
will raise RequestValidationException if theid
value is less or equals to0
.
Example: Validating byte arrays
In this example, we'll take a look at how to validate a request body received as a byte array. Suppose the server receives a POST
request with the following text data:
To receive data as a byte array and validate it, perform the following steps:
Receive data on the server side as follows:
post("/array") { val body = call.receive<ByteArray>() call.respond(String(body)) }To validate the received data, we'll use the second
validate
function overload that acceptsValidatorBuilder
and allows you to provide custom validation rules:install(RequestValidation) { validate { filter { body -> body is ByteArray } validation { body -> check(body is ByteArray) val intValue = String(body).toInt() if (intValue <= 0) ValidationResult.Invalid("A value should be greater than 0") else ValidationResult.Valid } } }