Spring Boot application with RESTEasy, Exposed, SQL Server written in Kotlin
Recently we have an opportunity to do a bit of exercise in freshening up our API tech stack especially in the microservices area. Our current tech stack is generally using Spring, RESTEasy, JPA (Hibernate) running on Tomcat written in Java 8 language. We want to transition to the embedded microservices world and see how Spring Boot fits into this plan with Kotlin as the new language of choice.
In this exercise, we want to replace Java with Kotlin, Tomcat with embedded Spring Boot , JPA(Hibernate) with Exposed while keeping RESTEasy, Spring Transaction, and Spring core framework as the glue to keep everything together. The architecture diagram below described how every component fits in the picture.
As our build tool, we will be using the old trusted Apache Maven.
Spring Boot
RESTEasy
Exposed
Kotlin
Creating Spring Boot app
As our base app, we are using the example Spring Boot app written in Kotlin from the Spring team.
Follow the tutorial and get the sample app running. This sample app is using Spring REST controller and JPA(Hibernate) running on H2 in-memory database
Adding RESTEasy
Next, we are going to replace Spring REST controller with RESTEasy. We will be using the RESTEasy Spring boot starter project.
pom.xml
Add the following dependency to the pom file.
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>3.0.0.Final</version>
<scope>runtime</scope>
</dependency>
RestEasyApplication.kt
Create a Kotlin file with the following content
import org.springframework.stereotype.Component
import javax.ws.rs.ApplicationPath
import javax.ws.rs.core.Application
@Component
@ApplicationPath("/rest-easy/")
class RESTEasyApplication : Application()
application.yaml
For RESTEasy integration, we will be using application.yaml format rather than properties
resteasy:
jaxrs:
app:
registration: property
classes: com.example.blog.RESTEasyApplication
management:
endpoints:
web:
exposure:
include:
- health
- shutdown
endpoint:
shutdown:
enabled: true
logging:
level:
org:
springframework: info
RESTEasy End Point
Create another file to describe our REST end point
import org.springframework.stereotype.Component
import javax.ws.rs.Consumes
import javax.ws.rs.GET
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.Produces
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
@Path("/blog")
@Component
@Produces(MediaType.APPLICATION_JSON)
class EchoEndpoint {
@GET
fun echoGET(): Response {
return Response.ok().entity(Message("Hello world!")).build()
}
}
Result
Build the app and run it. Go to the URL http://localhost:8080/rest-easy/blog/ and you should see the hello world message
Connecting to SQL Server using Exposed
Next we’ll try to connect our API to a SQL Server database using Exposed. We will also use spring transaction to manage db transactions and spring datasource to manage our db connection
Following on our base example app, create a table called articles in a test SQL Server database with the same structure. Insert a few test records into this table.
pom.xml
Add sql server jdbc driver and exposed dependencies
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.2.0.jre8</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>exposed</artifactId>
<version>0.13.7</version>
</dependency>
<dependency>
<groupId>org.jetbrains.exposed</groupId>
<artifactId>spring-transaction</artifactId>
<version>0.13.7</version>
</dependency>
Disconnect sample H2 DB
Comment out the db initialization steps done in BlogConfiguration.kt. Remove the h2 dependency from pom
Enable Spring datasource
Add the entry below to the application.yaml file
spring:
datasource:
url: jdbc:sqlserver://${sqlserver.url};instanceName=${sqlserver.instance};databaseName=${sqlserver.db.name}
username: ${sqlserver.db.username}
password: ${sqlserver.db.password}
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
logging:
level:
org:
springframework: info
jdbc:
datasource:
DataSourceTransactionManager: DEBUG
jetbrains:
exposed:
SpringTransactionManager: DEBUG
The db connection detail will be passed in as environment variables at runtime.
Enable Spring Transaction
@SpringBootApplication
@EnableTransactionManagement
@EnableConfigurationProperties(BlogProperties::class)
class BlogApplication {
@Bean
open fun transactionManager(dataSource: DataSource) = SpringTransactionManager(dataSource)
}
Exposed Table definition
Define our SQL Server tables in Kotlin
import org.jetbrains.exposed.sql.Table
import java.time.LocalDateTime
class Article(
val id: Long,
var title: String,
var headline: String,
var content: String,
var slug: String = title.toSlug(),
var addedAt: LocalDateTime = LocalDateTime.now()
)
object Articles : Table() {
val id = long("id").autoIncrement().primaryKey()
val title = text("title")
val headline = text("headline")
val content = text("content")
}
Spring repositories
interface ArticleRepository {
fun findAll(): List<Article>
}import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.selectAll
import org.springframework.stereotype.Repository
import org.springframework.transaction.annotation.Transactional
@Repository
@Transactional
class ArticleRepositoryImpl: ArticleRepository {
private fun fromRow(r: ResultRow) =
Article(r[Articles.id], r[Articles.title], r[Articles.headline], r[Articles.content])
override fun findAll() = Articles.selectAll().map { fromRow(it) }
}
RESTEasy End Point
Add another end point to fetch articles from SQL Server database
@Autowired
lateinit var repository: ArticleRepository@GET
@Path("/article")
fun articleGET(): Response {
var articles = repository.findAll();
return Response.ok().entity(articles).build()
}
Result
Run the application. Remember to pass in the db connection detail
java -Dsqlserver.url=[db-server] -Dsqlserver.instance=[db-instance] -Dsqlserver.db.name=[db-name] -Dsqlserver.db.username=[db-username] -Dsqlserver.db.password=[db-password] -jar .\target\blog-0.0.1-SNAPSHOT.jar
Open a browser and go to URL http://localhost:8080/rest-easy/blog/article.
Project sample code of this blog is available at
Closing thoughts & next steps
This exercise is the beginning of our learning on the Spring Boot, RESTEasy, and Exposed tech stack. So far this stack looks promising given that we are able to accomplished this much in a reasonable period of time without major roadblocks. There are plenty of examples on the web and this stack seems to be very well supported in the community. This is one stack which we’ll strongly consider for our production development.
Next steps include optimising Spring datasource, reducing Spring Boot footprint (starter project includes many other dependencies), disabling Spring annotation scanning for faster application start up.