Migrating from 1.6.x to 2.0.x
This guide provides instructions on how to migrate your Ktor application from the 1.6.x version to 2.0.x.
Ktor Server
Server code is moved to the 'io.ktor.server.*' package
To unify and better distinguish the server and client APIs, server code is moved to the io.ktor.server.* package (KTOR-2865). This means that you need to update dependencies for and imports in your application, as shown below.
Dependencies
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
Imports
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
WebSockets code is moved to the 'websockets' package
WebSockets code is moved from http-cio to the websockets package. This requires updating imports as follows:
1.6.x | 2.0.0 |
|---|---|
|
|
Note that this change also affects the client.
Feature is renamed to Plugin
In Ktor 2.0.0, Feature is renamed to Plugin to better describe functionality that intercepts the request/response pipeline (KTOR-2326). This affects the entire Ktor API and requires updating your application as described below.
Imports
Installing any plugin requires updating imports and also depends on moving server code to the io.ktor.server.* package:
1.6.x | 2.0.0 |
|---|---|
|
|
Custom plugins
Renaming Feature to Plugin introduces the following changes for API related to custom plugins:
The
ApplicationFeatureinterface is renamed toBaseApplicationPlugin.The
Featurespipeline phase is renamed toPlugins.
Content negotiation and serialization
Content negotiation and serialization server API was refactored to reuse serialization libraries between the server and client. The main changes are:
ContentNegotiationis moved fromktor-server-coreto a separatektor-server-content-negotiationartifact.Serialization libraries are moved from
ktor-*to thektor-serialization-*artifacts also used by the client.
You need to update dependencies for and imports in your application, as shown below.
Dependencies
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
|
| |
|
| |
|
| |
|
|
Imports
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
|
| |
|
| |
|
|
Custom converters
Signatures of functions exposed by the ContentConverter interface are changed in the following way:
Testing API
With v2.0.0, the Ktor server uses a new API for testing, which solves various issues described in KTOR-971. The main changes are:
The
withTestApplication/withApplicationfunctions are replaced with a newtestApplicationfunction.Inside the
testApplicationfunction, you need to use the existing Ktor client instance to make requests to your server and verify the results.To test specific functionalities (for example, cookies or WebSockets), you need to create a new client instance and install a corresponding plugin.
Let's take a look at several examples of migrating 1.6.x tests to 2.0.0:
Basic server test
In the test below, the handleRequest function is replaced with the client.get request:
x-www-form-urlencoded
In the test below, the handleRequest function is replaced with the client.post request:
multipart/form-data
To build multipart/form-data in v2.0.0, you need to pass MultiPartFormDataContent to the client's setBody function:
JSON data
In v.1.6.x, you can serialize JSON data using the Json.encodeToString function provided by the kotlinx.serialization library. With v2.0.0, you need to create a new client instance and install the ContentNegotiation plugin that allows serializing/deserializing the content in a specific format:
Preserve cookies during testing
In v1.6.x, cookiesSession is used to preserve cookies between requests when testing. With v2.0.0, you need to create a new client instance and install the HttpCookies plugin:
WebSockets
In the old API, handleWebSocketConversation is used to test WebSocket conversations. With v2.0.0, you can test WebSocket conversations by using the WebSockets plugin provided by the client:
DoubleReceive
With v2.0.0, the DoubleReceive plugin configuration introduces the cacheRawRequest property, which is opposite to receiveEntireContent:
In v1.6.x, the
receiveEntireContentproperty is set tofalseby default.In v2.0.0,
cacheRawRequestis set totrueby default. ThereceiveEntireContentproperty is removed.
Forwarded headers
In v2.0.0, the ForwardedHeaderSupport and XForwardedHeaderSupport plugins are renamed to ForwardedHeaders and XForwardedHeaders, respectively.
Caching headers
The options function used to define caching options now accepts the ApplicationCall as a lambda argument in addition to OutgoingContent:
Conditional headers
The version function used to define a list of resource versions now accepts the ApplicationCall as a lambda argument in addition to OutgoingContent:
CORS
Several functions used in CORS configuration are renamed:
host->allowHostheader->allowHeadermethod->allowMethod
MicrometerMetrics
In v1.6.x, the baseName property is used to specify the base name (prefix) of Ktor metrics used for monitoring HTTP requests. By default, it equals to ktor.http.server. With v2.0.0, baseName is replaced with metricName whose default value is ktor.http.server.requests.
Ktor Client
Requests and responses
In v2.0.0, API used to make requests and receive responses is updated to make it more consistent and discoverable (KTOR-29).
Request functions
Request functions with multiple parameters are deprecated. For example, the port and path parameters need to be replaced with a the url parameter exposed by HttpRequestBuilder:
The HttpRequestBuilder also allows you to specify additional request parameters inside the request function lambda.
Request body
The HttpRequestBuilder.body property used to set the request body is replaced with the HttpRequestBuilder.setBody function:
Responses
With v2.0.0, request functions (such as get, post, put, submitForm, and so on) don't accept generic arguments for receiving an object of a specific type. Now all request functions return a HttpResponse object, which exposes the body function with a generic argument for receiving a specific type instance. You can also use bodyAsText or bodyAsChannel to receive content as a string or channel.
With the ContentNegotiation plugin installed, you can receive an arbitrary object as follows:
Streaming responses
Due to removing generic arguments from request functions, receiving a streaming response requires separate functions. To achieve this, functions with the prepare prefix are added, such as prepareGet or preparePost:
The example below shows how to change your code in this case:
You can find the full example here: Streaming data.
Response validation
With v2.0.0, the expectSuccess property used for response validation is set to false by default. This requires the following changes in your code:
To enable default validation and throw exceptions for non-2xx responses, set the
expectSuccessproperty totrue.If you handle non-2xx exceptions using
handleResponseExceptionWithRequest, you also need to enableexpectSuccessexplicitly.
HttpResponseValidator
The handleResponseException function is replaced with handleResponseExceptionWithRequest, which adds access to HttpRequest to provide additional information in exceptions:
Content negotiation and serialization
The Ktor client now supports content negotiation and shares serialization libraries with the Ktor server. The main changes are:
JsonFeatureis deprecated in favor ofContentNegotiation, which can be found in thektor-client-content-negotiationartifact.Serialization libraries are moved from
ktor-client-*to thektor-serialization-*artifacts.
You need to update dependencies for and imports in your client code, as shown below.
Dependencies
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
| n/a |
|
kotlinx.serialization |
|
|
Gson |
|
|
Jackson |
|
|
Imports
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
| n/a |
|
kotlinx.serialization |
|
|
Gson |
|
|
Jackson |
|
|
Bearer authentication
The refreshTokens function now uses the RefreshTokenParams instance as lambda receiver (this) instead of the HttpResponse lambda argument (it):
RefreshTokenParams exposes the following properties:
responseto access response parameters;clientto make a request to refresh tokens;oldTokensto access tokens obtained usingloadTokens.
HttpSend
The API of the HttpSend plugin is changed as follows:
Note that with v2.0.0 indexed access is not available for accessing plugins. Use the HttpClient.plugin function instead.
The HttpClient.get(plugin: HttpClientPlugin) function is removed
With the 2.0.0 version, the HttpClient.get function accepting a client plugin is removed. Use the HttpClient.plugin function instead.
Feature is renamed to Plugin
As for the Ktor server, Feature is renamed to Plugin in the client API. This might affect your application, as described below.
Imports
Update imports for installing plugins:
Subsystem | 1.6.x | 2.0.0 |
|---|---|---|
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
Custom plugins
The HttpClientFeature interface is renamed to HttpClientPlugin.
New memory model for Native targets
With v2.0.0, using the Ktor client on Native targets requires enabling the new Kotlin/Native memory model: Enable the new MM.
The 'Ios' engine is renamed to 'Darwin'
Given that the Ios engine targets not only iOS but other operating systems, including macOS, or tvOS, in v2.0.0, it is renamed to Darwin. This causes the following changes:
The
io.ktor:ktor-client-iosartifact is renamed toio.ktor:ktor-client-darwin.To create the
HttpClientinstance, you need to pass theDarwinclass as an argument.The
IosClientEngineConfigconfiguration class is renamed toDarwinClientEngineConfig.
To learn how to configure the Darwin engine, see the Darwin section.
WebSockets code is moved to the 'websockets' package
WebSockets code is moved from http-cio to the websockets package. This requires updating imports as follows:
1.6.x | 2.0.0 |
|---|---|
|
|
Default request
The DefaultRequest plugin uses a DefaultRequestBuilder configuration class instead of HttpRequestBuilder: