<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Thibaut Gilbert]]></title><description><![CDATA[I'm a mobile developer. Dealing with Kotlin Android and some other stuff]]></description><link>https://47tibo.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 04 Sep 2026 20:50:53 GMT</lastBuildDate><atom:link href="https://47tibo.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Easily integrate an unknown API into your Android app with Postman and OpenAPI]]></title><description><![CDATA[The problem
Swagger and OpenAPI have been here for a while now, and it has greatly improved the way backend teams expose, maintain, and, above all, communicate on their APIs.
As a frontend developer, I've worked on projects where backend people where...]]></description><link>https://47tibo.hashnode.dev/easily-integrate-unknown-api-into-your-android-app-with-postman-and-openapi</link><guid isPermaLink="true">https://47tibo.hashnode.dev/easily-integrate-unknown-api-into-your-android-app-with-postman-and-openapi</guid><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[OpenApi]]></category><category><![CDATA[swagger]]></category><category><![CDATA[gradle]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Thibaut Gilbert]]></dc:creator><pubDate>Tue, 06 Feb 2024 15:58:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/bdOA_Twqz8k/upload/3812e327041b8f67527ad5823fac3f51.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-the-problem">The problem</h1>
<p>Swagger and OpenAPI have been here for a while now, and it has greatly improved the way backend teams expose, maintain, and, above all, communicate on their APIs.</p>
<p>As a frontend developer, I've worked on projects where backend people where just at the other side of the open space. So, each time a change in the API was available, the backend folks gently told us to regenerate the API interfaces based on a new version of the OpenAPI's definition file (<code>yaml</code> format).</p>
<p>This is standard procedure.</p>
<p>Unfortunately, on some of my personal projects, based on public APIs, I'm often unable to get my hands on the OpenAPI definitions. The only option left is to dive deep into the API's documentation, analyse HTTP responses in Postman and manually add DTOs to the data provider layer of my application. A bit frustrating, I admit...</p>
<p>After some research, I came across <a target="_blank" href="https://kevinswiber.github.io/postman2openapi/">this tool</a>. Basically it converts a Postman collection into an OpenAPI definition file.</p>
<p>That's a start, but how can we use it to integrate an arbitrary HTTP response into an application ?</p>
<p>Let's see this in practice.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I take as an example an Android app I'm currently working on. It's a weather app, which relies on the <a target="_blank" href="https://openweathermap.org/">OpenWeather API</a>. It's a great API, whose free plan is perfectly fine for my needs.</div>
</div>

<h1 id="heading-postman-collection-to-the-rescue">Postman collection to the rescue</h1>
<p>As first step, I create a Postman collection containing a <code>GET</code> request and associate an example to it. Adding an example is <strong>mandatory</strong> if you want to properly generate the OpenAPI schema with the <em>postman2openapi</em> tool.</p>
<p>In the context of my Android app, I'm relying on the <a target="_blank" href="https://openweathermap.org/api/one-call-3">"OneCall" endpoint</a> of the OpenWeather API :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707215816476/85ab81f7-2da6-4cf8-ad40-f3ab82f9a572.png" alt class="image--center mx-auto" /></p>
<p>The associated example is a JSON dump of Paris' weather data (short-term and long-term forecasts) :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707217194659/904ddbf2-8f2c-4b87-8ab7-9e96e9b55a7a.png" alt class="image--center mx-auto" /></p>
<p>After exporting the Postman collection, I simply copy/paste it into the <em>postman2openapi</em> tool, which instantly produces the OpenAPI definition file 😀.</p>
<h1 id="heading-integration-into-a-kotlin-android-app">Integration into a Kotlin Android app</h1>
<p>I then put those files into a specific folder, <code>open_weather_api</code>, at the root of my Gradle subproject :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707218715602/404ea409-cd13-424e-8860-20e715016a8c.png" alt class="image--center mx-auto" /></p>
<p>The <code>OpenWeather.yaml</code> file is paste "as is", <strong>except</strong> for the <code>tags</code> field that I add explicitly</p>
<pre><code class="lang-yaml"><span class="hljs-attr">servers:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://api.openweathermap.org</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/data/2.5/onecall:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">one</span> <span class="hljs-string">call</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">one</span> <span class="hljs-string">call</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">oneCall</span>
      <span class="hljs-attr">tags:</span> <span class="hljs-comment"># add "tags" manually</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">weather</span> 
      <span class="hljs-attr">parameters:</span>
</code></pre>
<p>This simple trick allows to override the name of the generated API interface name, for me <code>WeatherApi.kt</code> (instead would be <code>DefaultApi.kt</code>).</p>
<p>The <code>template/</code> directory contains OpenAPI's mustache templates I've generated and modified for my specific needs. For example, I've marked all the Kotlin <code>data class</code> (which are the programmatic representation of DTOs) as <code>internal</code>.</p>
<h1 id="heading-openapi-gradle-configuration">OpenAPI Gradle configuration</h1>
<p>In an Android project, the OpenAPI generator can be integrated via the Gradle plugin <a target="_blank" href="https://plugins.gradle.org/plugin/org.openapi.generator">org.openapi.generator</a>, giving access to tasks and extending Gradle DSL. The following is the configuration I use for my project, you may find it helpful :</p>
<pre><code class="lang-kotlin">openApiGenerate {
    generatorName = <span class="hljs-string">"kotlin"</span>
    outputDir = <span class="hljs-string">"<span class="hljs-variable">$projectDir</span>"</span>
    templateDir = <span class="hljs-string">"<span class="hljs-variable">$projectDir</span>/open_weather_api/template"</span>
    inputSpecRootDirectory = <span class="hljs-string">"<span class="hljs-variable">$projectDir</span>/open_weather_api"</span>
    modelPackage = <span class="hljs-string">"com.tibo47.weatherPaname.weather.dataprovider.remote.dto"</span>
    apiPackage = <span class="hljs-string">"com.tibo47.weatherPaname.weather.dataprovider.remote.api"</span>
    modelNameSuffix = <span class="hljs-string">"Dto"</span>
    <span class="hljs-comment">// for details :  https://openapi-generator.tech/docs/globals/#available-global-properties</span>
    globalProperties = mapOf(
        <span class="hljs-string">"apis"</span> to <span class="hljs-string">""</span>,
        <span class="hljs-string">"models"</span> to <span class="hljs-string">""</span>,
        <span class="hljs-string">"modelDocs"</span> to <span class="hljs-string">"false"</span>,
        <span class="hljs-string">"apiDocs"</span> to <span class="hljs-string">"false"</span>,
    )
    additionalProperties = mapOf(
        <span class="hljs-string">"sourceFolder"</span> to <span class="hljs-string">"src/main/java"</span>,
        <span class="hljs-string">"useCoroutines"</span> to <span class="hljs-string">"true"</span>,
        <span class="hljs-string">"library"</span> to <span class="hljs-string">"jvm-retrofit2"</span>,
        <span class="hljs-string">"serializationLibrary"</span> to <span class="hljs-string">"kotlinx_serialization"</span>,
    )
}
</code></pre>
<p>I strongly advice you to have a look at the <code>globalProperties</code> documentation, which is a gold mine of information.</p>
<h1 id="heading-dtos-and-api-generation">DTOs and API generation 🚀</h1>
<p>The plugin exposes the task :</p>
<pre><code class="lang-bash">./gradlew openApiGenerate
</code></pre>
<p>This will generate the appropriate DTOs and the API interface file, configured to be a Retrofit implementation :</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">internal</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">WeatherApi</span> </span>{
    <span class="hljs-comment">/**
     * one call
     * one call
     * Responses:
     *  - 200: one call
     *
     * <span class="hljs-doctag">@param</span> lat  (optional)
     * <span class="hljs-doctag">@param</span> lon  (optional)
     * <span class="hljs-doctag">@param</span> appid  (optional)
     * <span class="hljs-doctag">@param</span> units  (optional)
     * <span class="hljs-doctag">@return</span> [OneCall200ResponseDto]
     */</span>
    <span class="hljs-meta">@GET(<span class="hljs-meta-string">"data/2.5/onecall"</span>)</span>
    <span class="hljs-keyword">suspend</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">oneCall</span><span class="hljs-params">(
        <span class="hljs-meta">@Query(<span class="hljs-meta-string">"lat"</span>)</span> lat: <span class="hljs-type">kotlin</span>.<span class="hljs-type">String</span>? = <span class="hljs-literal">null</span>,
        <span class="hljs-meta">@Query(<span class="hljs-meta-string">"lon"</span>)</span> lon: <span class="hljs-type">kotlin</span>.<span class="hljs-type">String</span>? = <span class="hljs-literal">null</span>,
        <span class="hljs-meta">@Query(<span class="hljs-meta-string">"appid"</span>)</span> appid: <span class="hljs-type">kotlin</span>.<span class="hljs-type">String</span>? = <span class="hljs-literal">null</span>,
        <span class="hljs-meta">@Query(<span class="hljs-meta-string">"units"</span>)</span> units: <span class="hljs-type">kotlin</span>.<span class="hljs-type">String</span>? = <span class="hljs-literal">null</span>,
    )</span></span>: Response&lt;OneCall200ResponseDto&gt;
}
</code></pre>
<p>Due to the <code>modelPackage</code> and <code>apiPackage</code> options, files will be written in the appropriate packages :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1707228625398/ad3d1b98-69c8-4749-9dec-4b6f6e33beb6.png" alt class="image--center mx-auto" /></p>
<p>Those files must be checked into Git and should be regenerated if necessary, when a change in the OpenWeather API happens (e.g on a version upgrade).</p>
<p>If you have a linter (I hope you have) you will encounter lots of formatting errors. You can either try to fix them by editing the OpenAPI's mustache templates (tedious) or ignore them altogether. I stick to the second solution, by configuring the <a target="_blank" href="https://github.com/jeremymailen/kotlinter-gradle">kotlinter-gradle</a> plugin I use in my stack :</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> fileTree = fileTree(<span class="hljs-string">"src/main"</span>)
fileTree.include(<span class="hljs-string">"**/*Dto.kt"</span>)
fileTree.include(<span class="hljs-string">"**/WeatherApi.kt"</span>)

tasks.withType&lt;LintTask&gt; {
    <span class="hljs-keyword">this</span>.source = <span class="hljs-keyword">this</span>.source.minus(fileTree).asFileTree
}

tasks.withType&lt;FormatTask&gt; {
    <span class="hljs-keyword">this</span>.source = <span class="hljs-keyword">this</span>.source.minus(fileTree).asFileTree
}
</code></pre>
<hr />
<p>I hope this article will help you to quickly and securely generate and use public APIs for your apps ✌️.</p>
<p>If you have feedbacks or questions, don't hesitate to hit the <em>Comments</em> button, floating around. I'm also on <a target="_blank" href="https://androiddev.social">Mastodon for Android</a>, under the id <code>47tibo</code> if you prefer.</p>
]]></content:encoded></item></channel></rss>