Jooby: Export your Java/Kotlin API to Swagger/RAML
Tags: jooby, kotlin, swagger, raml
Published: 2017-12-22 00:15:20

---
title: "Jooby: Export your Java/Kotlin API to Swagger/RAML"
published: true
description: Write your Java or Kotlin API and export to Swagger and RAML
tags: jooby, kotlin, swagger, raml
---

# Overview

Documentation is essential while writing software, specially if you write complex business requirements, open source software, APIs, etc..

> Everybody wants good documentation, but nobody wants to write it.

Writing good documentation is hard, takes time and always always get out of date.

I found these rules useful while writing documentation:

1. keep documentation simple (without being too simple)
2. treat documentation like a requirement
3. use a tool to keep documentation up to date

For example, JavaDoc (rule #3) it is a nice tool that:

- keep documentation close to source code
- generates a static site that reflect the current state of your source code

Of course, you need to keep JavaDoc comments updated but at least the documentation is close enough to your source code and for example can be enforced as part of development process via tooling and/or code reviews (rule #2).

In this post we are going export a [Jooby](http://jooby.org) API to Swagger and RAML.

# ApiTool

The [ApiTool](http://jooby.org/doc/apitool) module is similar to JavaDoc. It is a tool that scans your code and produces an intermediate representation that can be exported to Swagger or RAML.

The goals of the ApiTool module are:

- *Developer first*. You focus on your API and business requirements (don’t need to think about Swagger/RAML details).
- *Clean source code*. Your methods are not full of annotations.
- *Uses JavaDoc*. Documentation is extracted from existing JavaDoc comments (write documentation once).


# demo

We are going to mimic subset of the [Petstore](http://petstore.swagger.io/#) API demo from [swagger.io](https://swagger.io).

To make it a bit more fun we are going to:

- Write the API using [Kotlin](https://kotlinlang.or)
- Use [Jackson](http://jooby.org/doc/jackson) for JSON processing
- Use [Hikari](http://jooby.org/jdbc) database connection pool
- Run database migrations with [Flyway](http://jooby.org/doc/flyway)
- Access database with [Jdbi](http://jooby.org/doc/jdbi3)

Sounds like a lot, right? Luckily enough the API is just a couple of lines in [Jooby](http://jooby.org):

```kotlin
/**
 * Kotlin ApiTool.
 */
class App : Kooby({

    /** JSON: */
    use(Jackson())

    /** Database: */
    use(Jdbc())
    use(Flywaydb())
    use(Jdbi3()
            .doWith { jdbi ->
                jdbi.installPlugin(SqlObjectPlugin())
                jdbi.installPlugin(KotlinPlugin())
                jdbi.installPlugin(KotlinSqlObjectPlugin())
            }
            /** Simple transaction per request and bind the PetRepository to it:  */
            .transactionPerRequest(
                    TransactionalRequest()
                            .attach(PetRepository::class.java)
            ))

    /** Export API to Swagger and RAML: */
    use(ApiTool()
            .filter { r -> r.pattern().startsWith("/api") }
            .swagger()
            .raml())

    // Home page redirect to Swagger:
    get { Results.redirect("/swagger") }

    /**
     * Everything about your Pets.
     */
    path("/api/pet") {
        /**
         * List pets ordered by id.
         *
         * @param start Start offset, useful for paging. Default is `0`.
         * @param max Max page size, useful for paging. Default is `20`.
         * @return Pets ordered by name.
         */
        get {
            val db = require(PetRepository::class)

            val start = param("start").intValue(0)
            val max = param("max").intValue(20)

            db.list(start, max)
        }

        /**
         * Find pet by ID
         *
         * @param id Pet ID.
         * @return Returns `200` with a single pet or `404`
         */
        get("/:id") {
            val db = require(PetRepository::class)

            val id = param<Long>("id")

            val pet = db.findById(id) ?: throw Err(Status.NOT_FOUND)

            pet
        }

        /**
         * Add a new pet to the store.
         *
         * @param body Pet object that needs to be added to the store.
         * @return Returns a saved pet.
         */
        post {
            val db = require(PetRepository::class)

            val pet = body<Pet>()

            val id = db.insert(pet)

            Pet(id, pet.name)
        }

        /**
         * Update an existing pet.
         *
         * @param body Pet object that needs to be updated.
         * @return Returns a saved pet.
         */
        put {
            val db = require(PetRepository::class)

            val pet = body<Pet>()
            if (!db.update(pet)) {
                throw Err(Status.NOT_FOUND)
            }
            pet
        }

        /**
         * Deletes a pet by ID.
         *
         * @param id Pet ID.
         * @return A `204`
         */
        delete("/:id") {
            val db = require(PetRepository::class)

            val id = param<Long>("id")

            if (!db.delete(id)) {
                throw Err(Status.NOT_FOUND)
            }
            Results.noContent()
        }
    }
})
```

We install a couple of modules via [use](https://static.javadoc.io/org.jooby/jooby/1.2.3/org/jooby/Jooby.html#use-org.jooby.Jooby.Module-) method.

```kotlin
    /** JSON: */
    use(Jackson())

    /** Database: */
    use(Jdbc())
    use(Flywaydb())
    use(Jdbi3()
            .doWith { jdbi ->
                jdbi.installPlugin(SqlObjectPlugin())
                jdbi.installPlugin(KotlinPlugin())
                jdbi.installPlugin(KotlinSqlObjectPlugin())
            }
            /** Simple transaction per request and bind the PetRepository to it:  */
            .transactionPerRequest(
                    TransactionalRequest()
                            .attach(PetRepository::class.java)
            ))

```

The [Jackson](http://jooby.org/doc/jackson) module for JSON processing.

The [Jdbc](http://jooby.org/doc/jdbc) module creates a high performance connection pool using [Hikari](https://github.com/brettwooldridge/HikariCP). Database details (url, user, password) are listed in the `application.conf` file.

The [Flyway](http://jooby.org/doc/flyway) module picks the database created previously and run database migrations from the `src/resources/db/migration` directory.

The [Jdbi](http://jooby.org/doc/jdbi3) module gives you database access via DAO/Repository like classes. [Jdbi](http://jdbi.org) is also a very lightweight library you we must install or add new feature via `plugins`. We add here repository support and [Kotlin](https://kotlinlang.org) related plugins.

And finally we install the [ApiTool](http://jooby.org/doc/apitool):

```kotlin
    /** Export API to Swagger and RAML: */
    use(ApiTool()
            .filter { r -> r.pattern().startsWith("/api") }
            .swagger()
            .raml())
```

We don't want to export ALL our routes, only those under the `/api` path and that is what the `filter` line does.

The calls `swagger()` and `raml()` export our API to those formats.

If you run the application you should see something like:

![Jooby+Swagger](http://jooby.org/resources/images/apitool-swagger.png)


# apitool goals

Let's review one of the routes:

```kotlin
   /**
     * Everything about your Pets.
     */
    path("/api/pet") {
        /**
         * List pets ordered by id.
         *
         * @param start Start offset, useful for paging. Default is `0`.
         * @param max Max page size, useful for paging. Default is `20`.
         * @return Pets ordered by name.
         */
        get {
            val db = require(PetRepository::class)

            val start = param("start").intValue(0)
            val max = param("max").intValue(20)

            db.list(start, max)
        }
    ...
```

As promised the ApiTool module

- let you focus on your API,
- keep the code clean and
- complement the output with JavaDoc comments.

There is nothing related to Swagger/RAML in the source code.

# final note

The [ApiTool](http://jooby.org/doc/apitool) module automatically exports your API to Swagger/RAML. You don't need to waste time adding anything extra.

There is a bit of overhead while running the application in development mode, due the [ApiTool](http://jooby.org/doc/apitool) scans and analyzes the code to produce Swagger/RAML. This overhead is eliminated once you deploy your application by adding a compile-time process to your Maven/Gradle project.

The [ApiTool](http://jooby.org/doc/apitool) also:

- Works with Kotlin and Java code
- Supports script/lambda routes, as well as Mvc routes

Source code is available [here](https://github.com/jooby-project/apitool-kotlin-starter)

Happy coding!