<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Maria Krol</title>
    <description>The latest articles on Forem by Maria Krol (@mariakrol).</description>
    <link>https://forem.com/mariakrol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1023330%2F0e8bdb20-e759-49b6-b80f-3b8310fb9921.jpeg</url>
      <title>Forem: Maria Krol</title>
      <link>https://forem.com/mariakrol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mariakrol"/>
    <language>en</language>
    <item>
      <title>Generate Kotlin client for a complex web API</title>
      <dc:creator>Maria Krol</dc:creator>
      <pubDate>Thu, 09 Feb 2023 17:36:01 +0000</pubDate>
      <link>https://forem.com/mariakrol/generate-kotlin-client-for-a-complex-web-api-1gff</link>
      <guid>https://forem.com/mariakrol/generate-kotlin-client-for-a-complex-web-api-1gff</guid>
      <description>&lt;p&gt;Automation for many routines starts with interaction via API. This case can be treated in many ways, but I want to take a look at interacting with web API using a generated Kotlin client.&lt;br&gt;
I found a lot of academic examples for generating Kotlin clients (most of them are based on the &lt;a href="https://petstore.swagger.io/" rel="noopener noreferrer"&gt;PetStore&lt;/a&gt;), but nothing was close to real-world examples.&lt;br&gt;
My goal is to build a Kotlin client for a complex API and see how it works.&lt;br&gt;
&lt;a href="https://github.com/mariakrol/open-api-playground" rel="noopener noreferrer"&gt;Here is the source code&lt;/a&gt; of the Kotlin project that I will use in the post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I chose the TeamCity API to play with. It is huge and complex, and also contains models with names that clash with built-in Java classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the goal? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A client has generated using the Kotlin language.&lt;/li&gt;
&lt;li&gt;The build task of the project depends on the generation of the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preparation &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Install TeamCity &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;All the examples have shown in this post are performed on a TeamCity installed on my machine.&lt;br&gt;
The installation process is fairly straightforward, and specific settings for the TeamCity installation process are beyond the scope of this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Take a look at the API &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;On the official TeamCity website we can find a lot of documentation about the API. In addition, we can see the automatically generated sources and find a path to the endpoint where the API schema is stored in Swagger format (&lt;code&gt;/app/rest/swagger.json&lt;/code&gt;).&lt;br&gt;
In the list of generated models, we can find types that have names that conflict with Java's built-in.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;TeamCity API Type&lt;/th&gt;
&lt;th&gt;Java Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.jetbrains.com/help/teamcity/rest/file.html" rel="noopener noreferrer"&gt;File&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;java.io.File&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.jetbrains.com/help/teamcity/rest/type.html" rel="noopener noreferrer"&gt;Type&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;java.lang.reflect.Type&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Failed to create a client for Java. The generator imports Java's types instead of TeamCity's.&lt;br&gt;
There are bugs described for the Java client in both the &lt;a href="https://github.com/swagger-api/swagger-codegen/issues/8134" rel="noopener noreferrer"&gt;Swagger generator&lt;/a&gt; and the &lt;a href="https://github.com/OpenAPITools/openapi-generator/issues/5083" rel="noopener noreferrer"&gt;OpenAPI generator&lt;/a&gt;. Let's see how the generator behaves when building a Kotlin client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate Kotlin client &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generate the client with the default settings of the generator &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/mariakrol/open-api-playground/tree/generate-client-with-jvm-okhttp4--SUCCESS" rel="noopener noreferrer"&gt;The source code&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Create a project &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Let’s start with the creation of a project. We have used the basic template of the project with Kotlin language and Gradle as a build system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx23o4kihw8psl2ntlk0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx23o4kihw8psl2ntlk0a.png" alt="Settings of the new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We need to add the API Schema file to the project's resources:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyqz0o8ulpmxxhuczjcp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyqz0o8ulpmxxhuczjcp.png" alt="API schema in the resources"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Choose a Generator &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We have two different generators to choose from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/swagger-api/swagger-codegen" rel="noopener noreferrer"&gt;Swagger Codegen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/OpenAPITools/openapi-generator" rel="noopener noreferrer"&gt;OpenAPI Generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main difference is described &lt;a href="https://openapi-generator.tech/docs/faq/#what-is-the-difference-between-swagger-codegen-and-openapi-generator" rel="noopener noreferrer"&gt;on the official page&lt;/a&gt; of the OpenAPI generator:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What is the difference between Swagger Codegen and OpenAPI Generator?&lt;/em&gt;&lt;br&gt;
Swagger Codegen is driven by SmartBear while OpenAPI Generator is driven by the community. More than 40 top contributors and template creators of Swagger Codegen have joined OpenAPI Generator as the founding team members. For more details, see the Fork Q&amp;amp;A.&lt;br&gt;
Swagger is a trademark owned by SmartBear and the use of the term "Swagger" in this project is for demo (reference) purposes only.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both generators do not work with the TeamCity API out of the box. For the OpenAPI generator, all problems are infrastructure related: The generator produces invalid Kotlin code with some combinations of libraries, and some other combinations produce valid code, but the environment (HTTP clients or serializers) cannot be fine-tuned. The Swagger generator produces invalid Kotlin code not related to libraries or settings: for example, variable names were generated with dashes.&lt;br&gt;
So let's go with the OpenAPI generator.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generation process &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We need to add the OpenAPI plugin to Gradle. (&lt;a href="https://search.maven.org/artifact/org.openapitools/openapi-generator" rel="noopener noreferrer"&gt;plugin page in MavenCentral&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jvm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.8.0"&lt;/span&gt;
   &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.openapi.generator"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"6.3.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we need to set up the task of the generator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;select the language;&lt;/li&gt;
&lt;li&gt;pass path to file with API specification;&lt;/li&gt;
&lt;li&gt;pass path where to put generated sources;&lt;/li&gt;
&lt;li&gt;select names of packages with generated code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We need to run the target task in Gradle to check the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9o2y29zs64qmqkj4at2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9o2y29zs64qmqkj4at2j.png" alt="OpenAPI generator task in Gradle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process fails, we get the error &lt;code&gt;Out of memory. Java heap space&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhibl1t0d9trav0n8sb40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhibl1t0d9trav0n8sb40.png" alt="Java heap out of memory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gradle uses a &lt;a href="https://docs.gradle.org/current/userguide/build_environment.html#sec:configuring_jvm_memory" rel="noopener noreferrer"&gt;default value of 512 Mb available&lt;/a&gt; for the Java heap. This is not enough for the OpenAPI generator in IDEA to build the client. We can change the size of the Java heap as well as other Gradle parameters in the &lt;code&gt;gradle.properties&lt;/code&gt; file.&lt;br&gt;
I use a very simple selection algorithm:&lt;br&gt;
Every time I fail with the error, I increase the size of the heap to twice the size. 4Gb is not enough. You can play with the heap size between 4Gb and 8Gb to select a smaller value if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gradle.properties&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

org.gradle.jvmargs=-Xmx8192m


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now the process is finished successfully!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5r8zp6v7f3x3h14cdi0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5r8zp6v7f3x3h14cdi0.png" alt="Successfully generated"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Build the project &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We need to add the generated files to the list of source paths in order for them to be included in the compilation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedSourcesPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sourceSets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;srcDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$generatedSourcesPath/src/main/kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we need to add a dependency of the Kotlin compilation task on the generation of the client. The compilation process must be done after the generation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;KotlinCompile&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;configureEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"openApiGenerate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let's run the build process and observe the errors (required dependencies are not included). Go through the errors and add the dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unresolved reference: okhttp3 → &lt;a href="https://mvnrepository.com/artifact/com.squareup.okhttp3" rel="noopener noreferrer"&gt;add from mvnrepository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Unresolved reference: com.squareup.moshi → &lt;a href="https://mvnrepository.com/artifact/com.squareup.moshi/moshi-kotlin" rel="noopener noreferrer"&gt;add from mvnrepository&lt;/a&gt; (everything needed to build a generated client is in this package)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;testImplementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

   &lt;span class="c1"&gt;// OpenAPI client&lt;/span&gt;
   &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.squareup.okhttp3:okhttp:4.10.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.squareup.moshi:moshi-kotlin:1.14.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The second pass of the build is successful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Calling the API from the client &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Calling the API methods from the client is required to verify that the client works at runtime. I have chosen two endpoints to call: User and Project.&lt;br&gt;
To make it easier, let's add a small wrapper that will create a basic HTTP client and set it up initially:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseApiClient.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseApiClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConfigurationProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teamCityHost&lt;/span&gt;
       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;baseClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getApiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

       &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getApiClient&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The TeamCity Web API is protected by authorization. The OkHttpClient builder does not know anything about authorization. OkHttpClient can be extended with &lt;code&gt;interceptor&lt;/code&gt;, so we need to add our custom to pass authentication data.&lt;br&gt;
The correct way of authorization is a separate complex topic and it is beyond the scope of this post. I have implemented the simplest, but not the most appropriate way: TeamCity provides the ability to generate authorization tokens with long expiration, I created a token and use it to authorize my requests:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulhw9lj3ycrznys5k9g3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fulhw9lj3ycrznys5k9g3.png" alt="TeamCity authorization tokens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This static token is passed to the interceptor without refreshing and so on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AuthorizationInterceptor.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuthorizationInterceptor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Interceptor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Interceptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Chain&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;newRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;signedRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proceed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signedRequest&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer ${ConfigurationProvider.token}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Pass it to the client:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseApiClient.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getApiClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorizationInterceptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AuthorizationInterceptor&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;OkHttpClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authorizationInterceptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we can wrap any endpoint. Let's start with the UserAPI and create methods to create, get, and delete a user:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UserApiWrapper.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserApiWrapper&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseApiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userApi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserApi&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;newUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"userName"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
           &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"${("&lt;/span&gt;&lt;span class="n"&gt;fakeMail&lt;/span&gt;&lt;span class="s"&gt;".appendRandomNumericPostfix())}@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;userApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Call the API from a dummy test:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F843kfms59rfsjrh4r0e0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F843kfms59rfsjrh4r0e0.png" alt="Successful run of dummy test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user is successfully created. Let's continue with a TeamCity project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ProjectsApiWrapper.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProjectsApiWrapper&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseApiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;projectApi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ProjectApi&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProjectApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createProject&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;newProject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NewProjectDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"simple_tc_project"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;projectApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newProject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Project&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;projectApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projectName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The execution fails with the error &lt;code&gt;Platform class java.io.File requires explicit JsonAdapter to be registered&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk29byd4iizz2717zf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5sk29byd4iizz2717zf3.png" alt="Error: JsonAdapter is not registered"&gt;&lt;/a&gt;&lt;br&gt;
This happens because the Moshi library is used for serialization, and it cannot handle collections without explicitly registered adapters. This bug has already been &lt;a href="https://github.com/OpenAPITools/openapi-generator/issues/8560" rel="noopener noreferrer"&gt;reported in the repo&lt;/a&gt;.&lt;br&gt;
Since we do not create instances of Moshi that do the serialization (the generator does it under the hood), we cannot register adapters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fix the generated client by changing settings &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We are faced with the problem described above when using a client generated with default settings. Now we need to check the settings of the generator to use something else for serialization.&lt;br&gt;
The OpenAPI generator has a &lt;a href="https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/kotlin.md" rel="noopener noreferrer"&gt;lot of different settings&lt;/a&gt;. But most interesting for us now is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;library&lt;/strong&gt; - This setting is used to control a whole set of libraries used to generate a client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;serializationLibrary&lt;/strong&gt; - This setting controls only one serialization library. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we can go in two different ways: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the setting &lt;code&gt;serializationLibrary&lt;/code&gt; to replace the Moshi library with something else and continue to use OkHttp for HTTP client&lt;/li&gt;
&lt;li&gt;use the setting &lt;code&gt;library&lt;/code&gt; and replace the whole group of libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Use setting ‘serializationLibrary’ to replace the Moshi library &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;First I try to replace the serialization library. The setting ‘serializationLibrary’ has 3 different values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/square/moshi" rel="noopener noreferrer"&gt;moshi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/gson" rel="noopener noreferrer"&gt;gson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/FasterXML/jackson" rel="noopener noreferrer"&gt;jackson&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one is not suitable for the current case, so let’s play with the two remaining.&lt;/p&gt;

&lt;h5&gt;
  
  
  Use &lt;code&gt;gson&lt;/code&gt; as serialization library &lt;a&gt;&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;To use the gson library, we need to add the dependency for it and change the settings of the task of the OpenAPI generator:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.google.code.gson:gson:2.10.1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedSourcesPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;configOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"serializationLibrary"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"gson"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The process of building this configuration goes successfully, we can start testing and see the green result!&lt;/p&gt;

&lt;h5&gt;
  
  
  Use &lt;code&gt;jackson&lt;/code&gt; as a serialization library &lt;a&gt;&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;Now I try to do the same for the &lt;code&gt;jackson&lt;/code&gt; library. Here are the dependency and the settings of the generator:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedSourcesPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;configOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"serializationLibrary"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"jackson"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The build and test processes have also been successfully completed!&lt;/p&gt;

&lt;h4&gt;
  
  
  Use setting &lt;code&gt;library&lt;/code&gt; to replace the whole set of libraries required for the generation process &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;library&lt;/code&gt; setting has many possible values. Each value describes the platform, library for HTTP client, and library for serialization:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;HTTP Client&lt;/th&gt;
&lt;th&gt;JSON processor&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;jvm-ktor&lt;/td&gt;
&lt;td&gt;Java Virtual Machine&lt;/td&gt;
&lt;td&gt;Ktor&lt;/td&gt;
&lt;td&gt;Gson, Jackson&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jvm-okhttp4&lt;/td&gt;
&lt;td&gt;Java Virtual Machine&lt;/td&gt;
&lt;td&gt;OkHttp&lt;/td&gt;
&lt;td&gt;Moshi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jvm-okhttp3&lt;/td&gt;
&lt;td&gt;Java Virtual Machine&lt;/td&gt;
&lt;td&gt;OkHttp&lt;/td&gt;
&lt;td&gt;Moshi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jvm-retrofit2&lt;/td&gt;
&lt;td&gt;Java Virtual Machine&lt;/td&gt;
&lt;td&gt;Retrofit&lt;/td&gt;
&lt;td&gt;Moshi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;multiplatform&lt;/td&gt;
&lt;td&gt;Kotlin multiplatform&lt;/td&gt;
&lt;td&gt;Ktor&lt;/td&gt;
&lt;td&gt;Kotlinx Serialization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jvm-volley&lt;/td&gt;
&lt;td&gt;JVM for Android&lt;/td&gt;
&lt;td&gt;Volley&lt;/td&gt;
&lt;td&gt;gson&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jvm-vertx&lt;/td&gt;
&lt;td&gt;Java Virtual Machine&lt;/td&gt;
&lt;td&gt;Vert.x Web Client&lt;/td&gt;
&lt;td&gt;Moshi, Gson or Jackson&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The setting  &lt;code&gt;jvm-okhttp4&lt;/code&gt; which is used by default was covered by the previous paragraph. Since the platform, I use for the playground is JVM, we cannot try to use jvm-volley. &lt;br&gt;
The remaining cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jvm-ktor&lt;/li&gt;
&lt;li&gt;multiplatform&lt;/li&gt;
&lt;li&gt;jvm-vertx&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Using &lt;code&gt;jvm-ktor&lt;/code&gt; group to generate: invalid Kotlin code &lt;a&gt;&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://github.com/mariakrol/open-api-playground/tree/generate-client-with-jvm-ktor--FAIL" rel="noopener noreferrer"&gt;The source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I start with &lt;code&gt;jvm-ktor&lt;/code&gt;. The official documentation says that it uses &lt;code&gt;jackson&lt;/code&gt; for serialization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedSourcesPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;configOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"library"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"jvm-ktor"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Build the project. We can find errors regarding dependencies (we did not add a required set), and invalid Kotlin code: classes that describe endpoints of the API pass non-existent parameters to the superclass:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rsub198le2pg9me92un.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rsub198le2pg9me92un.png" alt="Unexpected parameter"&gt;&lt;/a&gt;&lt;br&gt;
So, that case is useless for Kotlin clients now.&lt;/p&gt;

&lt;h5&gt;
  
  
  Using the &lt;code&gt;multiplatform&lt;/code&gt; group to generate: native Kotlin variant &lt;a&gt;&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://github.com/mariakrol/open-api-playground/tree/generate-client-with-multiplatform--SUCCESS" rel="noopener noreferrer"&gt;The source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s try to use the &lt;code&gt;multiplatform&lt;/code&gt; group of libraries:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;generatedSourcesPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$buildDir/generated"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiDescriptionFile&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"$rootDir/src/main/resources/teamCityRestApi-v2018.1-swagger2.0.json"&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiRootName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.makrol.teamcity.api.client"&lt;/span&gt;

&lt;span class="nf"&gt;openApiGenerate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;generatorName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;inputSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiDescriptionFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;outputDir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedSourcesPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;apiPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.api"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;invokerPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.invoker"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;modelPackage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$apiRootName.model"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;configOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mapOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"library"&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="s"&gt;"multiplatform"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In case we build the project, we would see only errors related to missing dependencies and not Moshi in this list. Looks good. So let's add the dependencies. (&lt;a href="https://mvnrepository.com/artifact/io.ktor" rel="noopener noreferrer"&gt;io.ktor group in mvnrepository&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.ktor:ktor-client-core:$ktorVersion"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.ktor:ktor-client-content-negotiation:$ktorVersion"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.ktor:ktor-serialization-kotlinx-json:$ktorVersion"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we need to update the infrastructure. We have the interceptor for &lt;code&gt;OkHttp&lt;/code&gt; authorization. &lt;code&gt;Ktor&lt;/code&gt; allows us to use several different engines (as well as &lt;code&gt;OkHttp&lt;/code&gt;), but for authorization purposes it is better to use the &lt;code&gt;Auth&lt;/code&gt; plugin. &lt;/p&gt;

&lt;p&gt;The constructor of the endpoint class gets a builder as a parameter, let's prepare the required one using the authorization plugin:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseApiClient.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;setupConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpClientConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getClientConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getClientConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpClientConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;bearer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nf"&gt;loadTokens&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;BearerTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConfigurationProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;refreshToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Ktor&lt;/code&gt; generates asynchronous code, so all functions that call the API are marked with the &lt;code&gt;suspend&lt;/code&gt; keyword:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UserApiWrapper.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserApiWrapper&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseApiClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userApi&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;UserApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpClientConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;setupConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;// ****&lt;/span&gt;

   &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;newUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"userName"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"${("&lt;/span&gt;&lt;span class="n"&gt;fakeMail&lt;/span&gt;&lt;span class="s"&gt;".appendRandomNumericPostfix())}@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendRandomNumericPostfix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// ****&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We get runtime errors while trying to run tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error &lt;code&gt;SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".&lt;/code&gt; occurred because Ktor depends on SLF4J in runtime&lt;/li&gt;
&lt;li&gt;Error &lt;code&gt;Fail to prepare request body for sending. 
The body type is: class com.makrol.teamcity.api.client.model.User (Kotlin reflection is not available), with Content-Type: null.&lt;/code&gt; occurred because we did not add content negotiation and did not pass content-type header&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To fix the first one we need to add dependency. (&lt;a href="https://mvnrepository.com/artifact/org.slf4j/slf4j-simple" rel="noopener noreferrer"&gt;see in mvnrepository&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseApiClient.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.slf4j:slf4j-simple:$slf4jVersion"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To fix the second one, we need to configure content negotiation through the plugin and add the content type header. &lt;br&gt;
So we need to update the config builder:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BaseApiClient.kt&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getClientConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpClientConfig&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DefaultRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nf"&gt;bearer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nf"&gt;loadTokens&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;BearerTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConfigurationProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;refreshToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ContentNegotiation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We are faced with a &lt;code&gt;kotlinx.serialization.SerializationException&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs10jnbd72jl14d2hpdxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs10jnbd72jl14d2hpdxx.png" alt="Serialization exception"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/Kotlin/kotlinx.serialization#gradle-with-plugins-block" rel="noopener noreferrer"&gt;If we read the kotlinx documentation&lt;/a&gt;, we would find that we need to install a corresponding plugin (&lt;a href="https://mvnrepository.com/artifact/org.jetbrains.kotlin.plugin.serialization/org.jetbrains.kotlin.plugin.serialization.gradle.plugin" rel="noopener noreferrer"&gt;see in the mvnrepository&lt;/a&gt;). Let's add it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle.kts&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jvm"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.8.0"&lt;/span&gt;
   &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"plugin.serialization"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.8.10"&lt;/span&gt;

   &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.openapi.generator"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"6.3.0"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It works!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6730io0x0ayme6ga7ea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6730io0x0ayme6ga7ea.png" alt="Success with multiplatform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Using &lt;code&gt;jvm-vertx&lt;/code&gt; group to build: authorization is not supported &lt;a&gt;&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;The last option available is &lt;code&gt;jvm-vertx&lt;/code&gt;. &lt;a href="https://openapi-generator.tech/docs/generators/kotlin-vertx/" rel="noopener noreferrer"&gt;According to the documentation&lt;/a&gt;, the stability of the generator is "beta", but it &lt;a href="https://openapi-generator.tech/docs/generators/kotlin-vertx/#client-modification-feature" rel="noopener noreferrer"&gt;does not support authorization&lt;/a&gt; yet. Since the API we are playing with is secured, the option is not available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As you can see, to get a successfully generated Kotlin client, you have to spend some time and play a bit with the settings.&lt;br&gt;
The OpenAPI generator has rich configuration capabilities and it helps to solve a lot of problems, but there is no silver bullet and the settings I used to get a usable Kotlin client for TeamCity API may be useless in some other cases.&lt;br&gt;
By changing the generator settings, you can change a whole set of libraries used to generate a client (option &lt;code&gt;library&lt;/code&gt;) or you can change only the serializer (option &lt;code&gt;serializationLibrary&lt;/code&gt;).&lt;br&gt;
HTTP client was successfully built using &lt;code&gt;Ktor&lt;/code&gt; and &lt;code&gt;OkHttp&lt;/code&gt;. &lt;code&gt;Vert.x Web Client&lt;/code&gt; does not support authorization for now, so it cannot be used for the API explored in the post.&lt;br&gt;
JSON serialization has been successfully handled by kotlinx, gson, and jackson.&lt;br&gt;
Decisions about which libraries to use must be made in the context of a task and project.&lt;br&gt;
Using the &lt;code&gt;multiplatform&lt;/code&gt; group (with &lt;code&gt;Ktor&lt;/code&gt; and &lt;code&gt;Kotlinx&lt;/code&gt; under the hood) seems most appropriate if the entire codebase of the project is written in Kotlin. Also, &lt;code&gt;Ktor&lt;/code&gt; has a bit more flexible customization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.jetbrains.com/teamcity" rel="noopener noreferrer"&gt;https://www.jetbrains.com/teamcity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gradle.org/current/userguide/getting_started.html" rel="noopener noreferrer"&gt;https://docs.gradle.org/current/userguide/getting_started.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/OpenAPITools/openapi-generator/tree/master/docs" rel="noopener noreferrer"&gt;https://github.com/OpenAPITools/openapi-generator/tree/master/docs&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://swagger.io/tools/swagger-codegen/" rel="noopener noreferrer"&gt;https://swagger.io/tools/swagger-codegen/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://square.github.io/okhttp/" rel="noopener noreferrer"&gt;https://square.github.io/okhttp/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openapi-generator.tech/docs/configuration/" rel="noopener noreferrer"&gt;https://openapi-generator.tech/docs/configuration/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openapi-generator.tech/docs/usage/" rel="noopener noreferrer"&gt;https://openapi-generator.tech/docs/usage/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ktor.io/learn/" rel="noopener noreferrer"&gt;https://ktor.io/learn/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ktor.io/docs/getting-started-ktor-client.html" rel="noopener noreferrer"&gt;https://ktor.io/docs/getting-started-ktor-client.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md" rel="noopener noreferrer"&gt;https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vertx.io/docs/vertx-core/kotlin/" rel="noopener noreferrer"&gt;https://vertx.io/docs/vertx-core/kotlin/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kotlin</category>
      <category>openapi</category>
      <category>tutorial</category>
      <category>teamcity</category>
    </item>
  </channel>
</rss>
