Do you know that you can create a Kotlin DSL with a few lines of code? In this post, we will see how to create a DSL over theApache HttpComponents library
Kotlin is a JVM language. This is how is described in its page:
Statically typed programming language for modern multiplatform applications
100% interoperable with Java™ and Android™
It has a lot of features and you can use to build your Android apps. We will focus on Type Safe Builders the feature that let us create DSL
Defining a Kotlin DSL for a Rest Client
At the end of this post, we can write code like this with our Kotlin DSL
GET("http://www.google.com") { withParam("foo", "bar") withHeader("Accept", "text/plain") }
Looks like magic, doesn’t it?
First of all we will create our pom.xml
to add the dependencies and config the Kotlin jars
<project> <modelVersion>4.0.0</modelVersion> <groupId>es.rubenjgarcia</groupId> <artifactId>rest-dsl</artifactId> <version>0.1.0-SNAPSHOT</version> <properties> <kotlin.version>1.1.51</kotlin.version> </properties> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory> <testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory> <plugins> <plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <version>${kotlin.version}</version> <executions> <execution> <id>compile</id> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
In the directory src/main/kotlin
we will create the RestDSL.kt
with the next content
import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpRequestBase import org.apache.http.client.utils.URIBuilder import org.apache.http.impl.client.HttpClients import org.apache.http.util.EntityUtils class RestBuilder(private val request: HttpRequestBase) { private var params: List<Pair<String, String>> = emptyList() private var headers: List<Pair<String, String>> = emptyList() fun withParam(name: String, value: String) { this.params = this.params + Pair(name, value) } fun withHeader(name: String, value: String) { this.headers = this.headers + Pair(name, value) } fun exec(): HttpResponse { val httpclient = HttpClients.createDefault() if (params.isNotEmpty()) { val uriBuilder = URIBuilder(request.uri) for ((first, second) in params) { uriBuilder.addParameter(first, second) } request.uri = uriBuilder.build() } for ((first, second) in headers) { request.addHeader(first, second) } httpclient.execute(request).use { r -> val entity = r.entity EntityUtils.consume(entity) return r } } } fun GET(url: String, init: RestBuilder.() -> Unit) = RestBuilder(HttpPost(url)).apply(init).exec()
Let me explain the code
- The function
GET
receives a String and a lambda expression. The magic is in the lambda expressioninit
. Everything inside has a reference to the RestBuilder object so we can invoke functions in a DSL way. Weapply
(invoke) the function and then we call theexec
function - We have 2 functions
withParam
andwithHeader
to add params and headers to our request - The function
exec
is where we execute the call. We add the params and the headers using the API provided by the Apache HttpComponents library and return the response
As you can see it’s easy to create a Kotlin DSL to implement the GET
function so now you can implement the other functions: POST
, DELETE
, PATCH
, …