Skip to content

Multiplatform Ktor schema declaration

Describe your Ktor API in code shared between the client and the server.

When creating fullstack projects, using both Ktor as a client and a server, we need to make sure we are calling the same endpoints on both sides, with the same expected DTOs, expect the same failures, etc.

Using Kotlin Multiplatform and KotlinX.Serialization, we can easily share DTOs—but the structure of the API isn't as easy to share.

Declaring a schema

Spine is a library to declare a schema of our API in pure Kotlin. Once it is declared, we can use it identically on the client and server sides.

First, declare a dependency on dev.opensavvy.spine:api.

We define that:

We can declare the structure of our API like this:

// Declare our root endpoint: /v1
object Api : RootResource("v1") {

    // Declare a nested resource: /v1/users
    object Users : StaticResource<Api>("/users", parent = Api) {

        // GET /v1/users
        // which returns a list of UserDto
        val list by get()
            .response<List<UserDto>>()

        // Declare a nested resource: /v1/users/{user}
        object User : DynamicResource<Users>("user", parent = Users) {

            // GET /v1/users/{user}
            // which returns a UserDto
            val get by get()
                .response<UserDto>()

            // POST /v1/users/{user}
            // which accepts a UserCreationDto and returns a UserDto
            val create by post()
                .request<UserCreationDto>()
                .response<UserDto>()

            // PUT /v1/users/{user}/friend
            val addFriend by put("friend")

            // DELETE /v1/users/{user}/friend
            val removeFriend by delete("friend")
        }
    }
}

We can then refer to any endpoint easily. For example, Api.Users.User.removeFriend is the DELETE /v1/users/{user}/friend endpoint.

Learn more

Resources describe a grouping of endpoints under a single URL:

  • RootResource is the root of a URL.

  • StaticResource is a hard-coded segment in a URL, for example /users or /posts.

  • DynamicResource is a wildcard segment in a URL, which could be replaced by a user's ID, for example.

Endpoints describe a specific HTTP method along with its expected input and output types, parameters, etc.

To learn how to use the APIs on the client or on the server, see the documentation of the client and server modules.

Packages

opensavvy.spine.api