Build REST Service with Kotlin, Spark Java and Requery — Part 2

Vaclav Souhrada
7 min readMar 19, 2017

--

In the previous part 1 you learned how to create and set up a new Kotlin Gradle project. Next, you got an introduction to the Spark Java Micro Framework and you learned how REST API can be created in the Spark.

In this article, we are going to make an extension of our example from part 1 to making it more realistic. You will add POJO objects, learn how to working with the ResponseTransformer in Spark and how to use popular DI library Dagger 2 with Kotlin and Retrofit libary for REST communication with the GitHub.

List of all parts:

Description of Demo Service in part 2

We will continue with our service from part 1. Our goal will be to implement a service that provides a basic information about GitHub user and his followers and repositories via REST.

Retrofit & GitHub REST API

In the first step we will create REST API for communication between our “micro” service and GitHub by utilization of the Retrofit library. If you are not familiar with the Retrofit, so please read an official documentation here first.

Spark offers to us handle requests and responses to/from our service but if we need communication with another service or server so it’s up to us what framework/library we choose to use for communication.

REST GitHub API which we will use:

https://api.github.com/users/{user} // Get user i.e vsouhrada :)https://api.github.com/users/{user}/repos // Get repositorieshttps://api.github.com/users/{user}/followers // Get Followers

Add dependency to project (build.gradle)

buildscript {
...
ext.retrofit_version = '2.2.0'
ext.gson_version = '2.6.2'
...
}
....
dependencies {
...
compile "com.squareup.retrofit2:retrofit:$retrofit_version"
compile "com.squareup.retrofit2:converter-gson:$retrofit_version"
}

You can see that we also added GSON Converter dependency to our project. We will use it later as converter factory when we will configure the Retrofit GitHubRestService.

Now it’s time to define POJO’s objects to which Retrofit will convert JSON from GitHub. Here are:

Next create a new interface GitHubRestService.kt (Retrofit service):

and define these functions:

The Retrofit configuration we will do in next section. It will be nicer if we define some Kotlin file where we REST constants will be store:

// package in my case cz.kotliners.kotlin.spark_requery.rest
// GitHubApi.kt
const val GH_URL = "https://api.github.com/"

const val
GET_GH_USER = "users"
const val
GET_GH_USER_REPOS = "users/{user}/repos"
const val
GET_GH_USER_FOLLOWERS = "users/{user}/followers"

Dagger 2: Dependency Injection (DI)

Dagger is a dependency injection framework created by Google (First version Dagger 1 was created by the Square Inc.). It is built on the standard javax.inject annotations (JSR 330). I will not explain Dagger in this article. If you are not familiar with Dagger, please read documentation or try to search on Google where you can find a lot of articles about it. Only I will mention what is @Module and @Component in the Dagger world:

  • Module: Provides dependencies by using @Provides annotation
  • Component: It is a bridge between modules and injections

Only what I must mention is that Kotlin has its own Annotation Processing Tool for Kotlin ->KAPT (you may know APT for Java)

Add Dagger 2 dependency to build.gradle and apply kotlin-kapt plugin:

buildscript {
...
ext.dagger_version = '2.4'
...
}
...
apply plugin: 'kotlin-kapt'...dependencies {
...
// Dagger DI
compile "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"

...
}

The generated code should be available when you sync/build your project.

Now create a new package injection with two sub packages component and module.

As you can see on image above you must create a new interface ServiceComponent and a class ServiceModule.

///// ServiceModule.kt@Module
class ServiceModule {

@Provides @Singleton fun provideGitHubRestService(): GitHubRestService {

return Retrofit.Builder()
.baseUrl(GH_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(GitHubRestService::class.java)
}
///// ServiceComponent.kt@Singleton
@Component(modules = arrayOf(ServiceModule::class))
interface ServiceComponent {

fun gitHubRestService(): GitHubRestService

Those of you who are familiar with Dagger already knows that Dagger will create (generate) a new class DaggerServiceComponent. This generated class have a builder to create an implementation of our ServiceComponent which we defined above.

To have DaggerServiceComponent available in our service we will create it in a static way. Kotlin doesn’t have static members like you know it from Java but has a special object — companion object.

class ServiceRunner {

companion object {
private val logger = LoggerFactory.getLogger(
ServiceRunner::class.java)

//platformStatic allow access it from java code
@JvmStatic lateinit var serviceComponent: ServiceComponent
}

init {
serviceComponent = DaggerServiceComponent.builder()
.serviceModule(ServiceModule())
.build()
}

We can call ServiceRunner.serviceComponent

Creating Internal Service

Our Rest API for communication with the GitHub is ready to use. We can @Inject GitHubRestService and start to using available REST methods, but it will be nice if we will have some “bridge” between ServiceController and GitHubRestService.

Create a new interface InternalService.kt

package cz.kotliners.kotlin.spark_requery.internal
...
interface InternalService {

fun getBasicUserInfo(user: String): BasicUserInfoDO

fun getUserRepositories(user: String): List<GitHubRepositoryDO>

fun getUserFollowers(user: String): List<GitHubFollowerInfoDO>

}

and impl. class InternalServiceImpl.kt:

The main goal of the InternalServiceImpl class is to call our GitHubRestService and map objects from this service to DO objects which will be returned by the ServiceController .

At line 4 we requesting dependency GitHubRestService. At line 7 we say to Dagger that we want to make an injection to InternalServiceImpl. To make injection working we need to add function inject to ServiceComponent.

@Singleton
@Component(modules = arrayOf(ServiceModule::class))
interface ServiceComponent {
... fun inject(serviceRunner: InternalServiceImpl)}

ServiceController

In the previous part 1, we created the ServiceController.kt where we defined one simple GET function
get(“/hello”, { req, res -> “Hello Spark!!!” })

In the previous section, we implemented InternalServiceImpl. Now we are ready to inject it to ServiceController and use it:

class ServiceController {

@Inject lateinit var service: InternalService

init {
ServiceRunner.serviceComponent.inject(this)

initRoutes()
}

private fun initRoutes() {

get("/user/:name", { req, res ->
service
.getBasicUserInfo(req.params(":name"))
})

get("/hello", { req, res -> "Hello Spark!!!" })
}

}

From code above you can see that I moved REST functions to a new function called initRoutes().

To get basic information about user (vsouhrada) we can put into browser this URL (of course run service before :) )

http://localhost:4567/user/vsouhrada

If everything is working you should see:

Hmmm, we have expected output but you may be asking that this doesn’t look likes as JSON format. You’re right! Our REST function doesn’t return the object as JSON, but object directly so what you can see in the image above is a result from toString() method. How to solve it? Spark has something what is called Response Transformer!

Response Transformer

ResponseTransformer is an interface defined in the Spark uses to convert objects returned by routes to an actual HTTP response. It has method that takes an object and returns a String representation of this object. So create a new Kotlin class JsonResponseTransformer.kt:

class JsonResponseTransformer : ResponseTransformer {

private val gson = Gson()

override fun render(model: Any?): String {
return gson.toJson(model)
}

}

We can make it a nicer little bit:

class JsonResponseTransformer : ResponseTransformer {

private val gson = Gson()

override fun render(model: Any?) = gson.toJson(model)

}

gson.toJson() is an universal method that converts an object to JSON using GSON.

Now modify ServiceController.kt:

class ServiceController {

...

private fun initRoutes() {
val gson = Gson()

get("/user/:name", routeUserInfo(), JsonResponseTransformer())

...
}

private fun routeUserInfo() = Route {
req, res -> service.getBasicUserInfo(req.params(":name")) }

}

and try to run service again… You should see now output in the JSON format:

{  
"login":"vsouhrada",
"url":"https://api.github.com/users/vsouhrada",
"repos_url":"https://api.github.com/users/vsouhrada/repos",
"name":"Vaclav Souhrada"
}

If you do not need any special code inside the ResponseTransformeror you can call Gson.toJson() directly in code

val gson = Gson()get("/user/:name", { req, res ->
service.getBasicUserInfo(req.params(":name"))
}, gson::toJson)

Another way could be to define json(obj: Any?) function:

get("/user/:name",{ req, res ->
service.getBasicUserInfo(req.params(":name"))
}, {obj -> toJson(obj)})
...
private fun toJson(obj: Any?) = gson.toJson(obj)

Or we can use an extension functions in Kotlin add toJson() function to all objects :):

get("/user/:name", { req, res ->
service.getBasicUserInfo(req.params(":name"))
}, { obj -> obj.toJSON() })
....fun Any.toJSON(): String {
return gson.toJson(this)
}

I let it up to you what kind of solution you choose for this simple demo. I will use the last one.

We still have to implement the remaining two methods, so final code (depends on a way what you decided to go) looks like:

Final code of the ServiceController.kt in part 2

Note: Please check a final code of this part 2. I made additional steps that I’m injection Gson to the ServiceController.kt , so I added @Provides function to the ServiceModule and ServiceComponent.

As a final step try to run a newly added functions i.e.:

http://localhost:4567/repos/vsouhradahttp://localhost:4567/followers/vsouhrada

Summary

As you can see create REST in Spark is very easy. In the previous part we set up project and you wrote a first Spark REST (Hello Spark). So our service allows REST calls.

In this article, we learned how we can create REST communication from our service to another service or public API (GitHub in our case). In that case, Spark doesn’t have any framework by default but it us up to us which framework we will use it for. In our case we used the Retrofit. Next, we looked how to use Dagger 2 with Kotlin.

That is almost all I wanted to show you :) But something is missing. In the next (last) article from this small series I would like to show you how you can write an easily persistent layer by using the Requery framework.

Thank you for reading and stay tuned …

Next article: Part 3: Persistent Layer by using the Requery — IN PROGRESS

--

--

Vaclav Souhrada

Android Developer | Kotlin enthusiast | Czech Kotlin User Group organizer (www.kotliners.cz)