How-To's

Introduction to Space Applications

With the official release fast approaching, we continue to add missing features to Space. One feature that was missing was the ability for third-party developers to extend Space. With the introduction of Space Applications, we’ve filled that gap.

In the JetBrains Space Extensibility Manifesto you can find all our plans regarding the ways you can extend Space in the future. For now, Applications are the only way to extend it.

Let’s take a look at what Applications are, and what you can do with them!

What are Space Applications?

A Space application is an external server-side service or client-side application (JavaScript, mobile, or desktop) that can interact with Space via the Space HTTP API.

Here are the main types of applications you can create for Space:

  1. Chatbots
    Chatbots are a familiar feature of Slack and Telegram. To interact with a bot, you send commands to the chatbot’s channel. If the command is recognized by the bot, it does something and then sends a message back to you.

  2. Slash commands
    Type / in a chat and the app will show you the list of commands available in the current context. Currently, this feature is available only for chatbots (only inside chatbot channels).

  3. (Planned) Custom menu items
    Extend any menu in Space with your own items.

  4. Client applications
    Applications that do not extend Space functionality but get various data from Space and use it for their own purposes.
  5. Any combination of the above.

What’s needed to start developing Space applications?

Here’s your starter kit:

  • IDE
    If you choose to develop your application in Java or Kotlin, IntelliJ IDEA is without a doubt the best choice. If you’re from the .NET world, then look no further than Rider or Visual Studio with ReSharper on board.
  • Space SDK
    The must-have for a Space application developer. As we mentioned, applications communicate with Space via a HTTP API. The SDK provides the API clients for Kotlin and .NET. It also provides a lot of other useful stuff, but more about that later.
    Note that in this post we’ll talk only about the Kotlin version of the Space SDK.
  • Ktor framework
    Your application will need to send and receive HTTP requests. Nowadays, such tasks are solved by web frameworks, and Ktor is one of the best choices. Aside from the fact that the Space SDK uses the Ktor HTTP client by default, Ktor is also just very cool in itself.
    If you’re working with .NET, you can use the ASP.NET HTTP client.
  • A tunneling service
    Sych a service exposes local servers to the public internet. It will let you run your applications locally and access them from Space via a public URL. For example, you can use ngrok. This is a paid service, but the free ngrok plan is sufficient for development purposes.

How to get started

We won’t go into all of the Space SDK internals in this post. For more information about the SDK, you can refer to the Space Applications documentation. The documentation is still a work in progress, but it already contains the minimum information you need to create a chatbot, add interactive UI elements to messages, get data from Space, and some other topics.

Let’s take a quick look at the Space SDK.

Where to get the Space SDK

  • Space SDK for Kotlin: packages | sources
    The easiest way to get SDK for Kotlin is to open HTTP API Playground and in the Kotlin SDK tab click the Setup dependency link.
  • Space SDK for .NET: packages | sources

What’s inside the Space SDK and how to use it

The main logical parts of the SDK are:

1. Space HTTP API client

The client lets your application authenticate in Space (note that to get app authentication credentials, you must first register your app in Space):

// HttpClient is a Ktor client
// clientId and clientSecret you get when register app in Space
val spaceClient = SpaceHttpClient(HttpClient())
        .withServiceAccountTokenSource(
                clientId, clientSecret, organizationUrl)

It gives access to all Space endpoints. All top-level endpoints are properties of the SpaceHttpApiClient class:

// get a member profile from Team Directory
val memberProfile = spaceClient.teamDirectory.profiles
        .getProfile(ProfileIdentifier.Username("John.Doe"))

You can use the Space HTTP API Playground as a reference for the client:
JetBrains Space. SDK client structure

2. Payloads SDK

This is a set of classes that help you process incoming requests from Space. To be more precise, it helps you process various types of payload. This part of the SDK is essential for creating chatbots, slash commands, and custom menus.

When a user performs an action related to your application (for example, sends a command to a bot, runs a slash command, or clicks on a custom menu item), Space sends a request to your application’s endpoint. The request carries the payload. Your task as an application developer is to analyze the payload.

For example, receiving a ListCommandsPayload means that a user pressed slash and wants to get the list of commands available in the current context:

fun Routing.backToSpace() {
    post("api/back-to-space") {
        val payload = readPayload(call.receiveText()) 
        val context = getCallContext(payload)

        if (payload is ListCommandsPayload) {
                call.respondText(jackson.writeValueAsString(commandListAllCommands(context)),
                        ContentType.Application.Json)
        }
     }
     ...
}

Actually, this type of payload is sent not only when a slash is typed, but when any key is pressed (the bot always returns the same list, but Space starts filtering this list using the pressed keys as a search pattern).

Receiving a MessagePayload means that a user typed some text to the bot’s channel, and our task is to analyze this text and, if it contains a command, run it:

           if (payload is MessagePayload) {
                val command = commands.find { it.name == payload.command() }

                if (command == null) {
                    commandHelp(context)
                } else {
                    launch { command.run(context, payload) }
                }
                call.respond(HttpStatusCode.OK, "")
            }

There are other types of payloads for different cases: interactive UI elements in messages, custom menus, and others.

3. Message builder

Messages in Space are not just plain text – they can use very complex formatting and even contain interactive UI elements, for example buttons. The message builder is a special DSL that you can use to construct such messages. For example, this is what a message with a button looks like:

fun helloMessage(): ChatMessage {
    return message {
        outline = MessageOutline(
            icon = ApiIcon("smile"),
            text = "This is the outline"
        )

        section {
            header = "This is the header"
            controls {
                helloButton("World!")
            }
        }
    }
}

fun MessageControlGroupBuilder.helloButton(payload: String) {
    val text = "Hello $payload"
    val style = MessageButtonStyle.PRIMARY
    val action = PostMessageAction("helloAction", payload)
    button(text, action, style)
}

The resulting message will look like this:

4. Various helper utils

These are classes that make your life easier by handling typical operations, such as serializing and deserializing JSON objects.

That concludes our brief overview of Space Applications. We hope it’s enough to get you interested! If you’ve always wanted to create something like a chatbot, now is the best time to give it a try.

If you have any questions or feedback, please leave them in the comments below.

image description