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
embeddedServerfunction call.... inside the explicitly defined
module, which is an extension function of theApplicationclass.
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
validateoverload 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 aStringvalue:install(RequestValidation) { validate<String> { bodyText -> if (!bodyText.startsWith("Hello")) ValidationResult.Invalid("Body text should start with 'Hello'") else ValidationResult.Valid } }If you have the
ContentNegotiationplugin installed configured with a specific serializer, you can validate object properties. Learn more from Example: Validating object properties.The second
validateoverload acceptsValidatorBuilderand 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
Customerdata class that describes the JSON object above:@Serializable data class Customer(val id: Int, val firstName: String, val lastName: String)Install the
ContentNegotiationplugin with the JSON serializer:install(ContentNegotiation) { json() }Receive the
Customerobject on the server side as follows:post("/json") { val customer = call.receive<Customer>() call.respond(customer) }In the
RequestValidationplugin configuration, add validation of theidproperty 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,
RequestValidationwill raise RequestValidationException if theidvalue 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
validatefunction overload that acceptsValidatorBuilderand 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 } } }