Kotlin WebApp Tutorial — ToDoList — Part 1

Creating REST services using SparkJava / Kotlin and Single Page App using VueJS

Wayne Ellis
10 min readAug 25, 2017

Not so long ago, I wrote a piece on creating a Websocket chat implementation using Kotlin and SparkJava. This was fun, and helped show the power of Kotlin in web development, but didn’t really hammer home why web development in Kotlin is a good thing. With so much being written and spoken about Kotlin in the Android world, I wanted to try to address the balance somewhat and put a little more weight onto the web dev argument for using Kotlin.

The following blog post will be split into two parts. Part 1 (this post) will be the REST backend, and Part 2 will be the VueJS client side. Full source code can be found here on GitHub. (update: I have added a Part 3 that uses SpringBoot instead of SparkJava, so you can compare implementations).

Set Up

As with last time, assuming you already have Kotlin up and running (I have used IntelliJ), first we will create a POM file. If you are using intelliJ, then create a Maven project, and copy the following code.

Some specific things to note here:

  1. JCenter as a repository has been included. This is because we are importing Fuel later for testing our REST routes, and Fuel is only available currently on JCenter and not maven central.
  2. The dependencies we have included are, in order; Kotlin, KotlinTest, SparkJava, HikariCP (for DB connection pooling), H2 (we will use an in memory DB to save us installing a specific database), kotliquery (a DB access library), SLF4J (for logging), Jackson (for JSON← →Object conversions), and finally Fuel (which is an HTTP client which we will use in our unit tests.

Again, just like last time, if you have set up the project as a Maven project, then you will have a standard maven directory structure. We will need to create two further directories.

  1. We need to create a directory called public inside of src\main\resources\
  2. We need to create a directory to put our package structure in. I have chosen to use a kotlin directory inside of src\main and src\testrather than using the normal src\main\java. We also need to add a package directory in both src\main and src\test. I have chosen codemwnci.

If you have chosen the same approach as me, you will now have a directory structure like the following

- src
- main
- kotlin
- codemwnci
- resources
- public
- test
- kotlin
- codemwnci

We are now ready to start our coding! So let’s begin with adding a database to store our ToDo’s in.

Add Database Support

So, let’s create a new Kotlin file, called MainController.kt

Copy the following code

This code hopefully is fairly self explanatory. We import all the necessary packages, and then within the main function (this will later contain our REST code) we call the setupDBfunction.

The setupDB function first of all creates a datasource. Hikari allows multiple data sources to be created, however, in our example we only need one, so we will set a default datasource with the URL required for an in memory H2, and any username / password. Next we make use of the datasource, using kotliquery.

Each kotliquery starts with the using statement and then inside the body of that statement, we use the session.run(queryOf().asExecute) statement. The asExecute is used for update statements, where as SELECT queries use a MAP and asSingle / asList method (we’ll come on to that shortly). So, here we execute a statement to create the TODO table with 4 columns (id, text, done and created_at).

And there we have it, we have database support configured with a data source, and fully configured database table set up and running in memory. Next we can start to populate the database!

Create A Todo (HTTP Post)

Firstly, remember that the database that we have configured is an in memory database. The data does not persist between server restarts. To do that, we would need to configure a different DB URL (and there would also be no need to run the CREATE TABLE sql every time the server started).

Anyhow, on to the code for our first REST service. First of all, let’s set up some utility functions. Add them just above the setupDB function.

fun badRequest(reason: String) = halt(400, reason)
fun serverError(reason: String) = halt(500, reason)

These are two very simple functions that allow us to break out of processing our routes under certain circumstances, and return a 400 / 500 code with an associated reason message. We’ll make use of these in our first route.

Now, let’s go back to to our main function and add the following code immediately after the setupDB call, so it looks like below.

Let’s dissect this code a little:

  1. Line 4: we set our code to run on port 9000 (I spent so long with PlayFramework, I can’t help it!)
  2. Line 5: here we set where our HTML / JS code will go. We won’t get to this until Part 2 of this blog, so ignore it for now.
  3. Line 7: all of our routes are going to be access via VERB /todo/<something> so rather than repeating the /todo/ part, we use the path to say that everything contained inside are child routes of /todo/ .
  4. Line 8: this is part of the reason I love Koltin. This would be a full class with setters / getters in Java. Here, we have our DTO that represents our Todo. If you use Scala, this is equivalent of a case class.
  5. Line 10: this is a simple function that converts a Row (DB Result Row) into a Todo, by accessing the database object and creating a new Todo object from the accessed data. We will use this next on Line 12.
  6. Line 11: This function takes an ID and returns a Todo (the return type is not null safe because it is possible the database does not contain that ID. Here we use the using statement we used to CREATE the database earlier.
  7. Line 12: here we run a select statement, passing in the ID that was passed into the function. We then map using the toTodo mapper we created in step 5 (line 10) and tell KotliQuery that we are expecting a single value using the asSingle terminator.

Now let’s dissect Line 15 to 24, which makes up the actual HTTP request that handles then HTTP Post to create a new Todo. Here, we expect a request to POST http://localhost:9000/todo/ with the text of the todo in the body of the request.

  1. Line 15: this is our POST method. We pass in the empty string, because we expect the post to be sent to /todo/.
  2. Line 16: we ensure that the body is not empty, and if it is we call the badRequest function we set up at the start of this section.
  3. Line 18: we get the todo from the body of the request
  4. Line 20: We run an insert statement to insert the todo text retrieved in Line 18. One thing to note here is instead of asExecute we use asUpdateAndReturnGeneratedKey. This returns the generated ID, which we store into the val idon line 19.
  5. Line 23: we do a simple check that the id is not null, to ensure the insert was successful. If it is null, we call the internalServerError function.
  6. Line 24: if all is successful, we use the jacksonObjectMapper to create a JSON representation of a Todo, which we retrieve from the database using the ID passed into the getTodo function that we created on Line 11/12. We load the full Todo from the database at this stage, to return because there are a number of database generated values (done / created_at), that we don’t have direct access to otherwise following a create.

And that is it. We can now using something like Postman to do a HTTP Post, and we should see a JSON string returned to us.

Get a Single Todo (HTTP Get)

To return a single Todo will be really easy, given that we have done most of the work already in the POST.

We just need to add the following code just underneath our previous post route, so that it is still inside of path scope.

There is not much to dissect here. the :id inside of the get identifies to the route that we expect a value to be passed in. This will be the ID of the specific ID we want to return. Next we call the getTodo that we used in the POST to return the created todo, except the ID that we pass into the function is retrieved from the request req parameter and convereted to a Long.

The Todo is then converted into JSON using jacksonObjectMapper as we did in the POST method.

Get All Todos (HTTP Get)

When we first load our todo app, we will want to return all the Todos, not one by one. So, let’s see if we can return all Todos and not just a single element.

We have already done a lot of the work, so again, this is pretty straightfoward. Add the following code after the GET from above (again, inside of the todo PATH).

  1. Line 2: note that we are List<Todo> from the SQL statement, rather than a single Todo like before.
  2. Line 3: we select all todos, we map using the same toTodo mapper that we used in the getTodo function, but we finish with asList indicating to KotliQuery that we expect a list of Todo objects to be returned from the query, therefore to iterate over the result set, rather than just getting a single item.
  3. Line 5: we use the jacksonObjectMapper to convert the List of Todos into JSON.

Job done! Easy.

Delete A Todo (HTTP Delete)

Next, we want to be able to delete todos when we are done with them. How frustrating would a todo list app be if we could never get rid of the todos!

Again, this is pretty straightforward now that we are getting the hang of using SparkJava and KotliQuery. We expect a HTTP Delete request to be sent to us with the ID of the todo we wish to delete.

Line 1: here we specify the route as a DELETE with an ID expected in the path.

Line 2 / 3: we run a delete query where the ID is equal to the ID that we passed in, and run the query as an Update. The asUpdate terminator results in an integer being returned with the number of affected rows (we store this in the rowsDeleted value).

Line 6: if we deleted a single row as expected, we simply return “ok” (note in Kotlin we don’t need to specify return. This “ok” will indicate to the client side that the delete was successful.

Line 7: if we did not delete a single row, then we return a server error 500, saying something went wrong.

Update A Todo (HTTP Put)

Finally, the only thing our server side does not take care of is updating of the todo (marking as done, or editing the todo text). To do that, we will use the HTTP PUT verb again with the ID as a path parameter, but with some JSON in the body of the request with the updated details.

Again, add the following code inside of the PATH parenthesise like we have done for all the other routes.

  1. Line 3: Here we create a value called update, which contains a JSON object that has been read from the body of the request. This contains the data that needs to be updated.
  2. Line 4: we check if the JSON contains both text and done, if not returning a badRequest.
  3. Line 6–9: resulting in a number of rows updated, we execute an update query, getting the text and boolean from the JSON and the ID from the request paramater, and then executing the SQL using asUpdate.
  4. Line 12: Just like on the DELETE statement, we check if we had a single row updated. If we did, we return the updated Todo by calling the getTodo function (like we did on the POST).
  5. Line 13: Otherwise, if we did not have a single row updated, we return that something went wrong.

And that is it. A complete REST App with 5 different routes to add, delete, update and read (one or all), in 90 or so lines of code. You can test all of this our using cURL or Postman or SoapUI. But, before we finish and start working on the client side, we really should test our code like every conscientious developer should.

Unit Testing using JUnit

Remember that we are using an in-memory database. This means that the database is freshly set up every time, which perfectly suits our unit-testing needs. If we start to use a real database, we would have to ensure that when we start our server, we do so with a test (clean) database rather than the development / production database.

Unlike the code above, which I broke down into manageable chunks, I am just going to dump the whole lot in one go, and explain it, as there is a lot of repetition as each route is tested in turn.

Create a new file in /src/test/kotlin/codemwnci/ called MainControllerTest.kt, and past the following code.

  1. Line 4: we are importing Fuel. This is an httpClient library that allows us to execute our HTTP routes. Spark does not come with a built in testing library like some HTTP frameworks, so we will use Fuel to do it for us.
  2. Line 10–21: This set of code starts and stops SparkJava ready for testing. Because our main function that contained our routes (in MainController.kt) is not within a Class boundary, it is referenced at package level therefore, in our BeforeClass, we can simply access it by calling main() and pass in an empty array. Also note that JUnit requires the BeforeClass / AfterClass to be in a companion object, and the functions marked as @JvmStatic.
  3. Line 30–33: I will highlight the second part of the first test to dive a little deeper into here. Line 30 we create an http request using Fuel to execute a post request, and setting the body with the text of the todo. This returns a Triple (request, response, result). On Line 31 we use the response (accessed from post1.second), because response is the second element of the triple, and then we check the httpStatus code is 200 indicating a successful post. We then get the data from the result (post1.third.get()) , convert it to JSON, and check that the generated ID is 1.

The rest of the tests are along similar lines. Making requests, and checking the httpStatus from the response, or reading the result and checking the data is as we expected.

Again, remember that this is all possible because the database starts afresh each time we start the server. If we had a permanent database behind it, this would not work as it stands, and we would have to ensure that when started up the server (via the main method), we passed in parameters that ensured that app knew it had to start up in Test mode.

And That’s All for Part 1

Thanks for reading, and please come back to read more in Part 2 when we take a look at the client side in VueJS to consume our REST services.

--

--

Wayne Ellis

Software Architect; Author of Introducing the Play Framework; Technologist.