Receive Payload from Space
With some types of applications, Space acts as a client – it sends POST requests to the application endpoint with JSON payload inside. For example, when a user types in the application chat channel, Space sends payload containing the user input; if the application is subscribed to webhook notifications, Space sends payload with event details, and so on.
Payload contents
The payload consists of the name of a payload class, class-specific payload data, and data that is common for all payload types (like Space URL, user ID, and so on).
For example, this is a sample payload from Space when a user sends help
command to a chatbot:
{
// [[[Payload class|#payload-classes]]]
"className": "MessagePayload",
// Class-specific payload data
"message": {
"messageId": "CsT000CsT",
"channelId": "3FhQeS2URbeY",
"messageData": null,
"body": {
"className": "ChatMessage.Text",
"text": "help "
},
"attachments": null,
"externalId": null,
"createdTime": "2021-05-21T17:01:33.767Z"
},
// [[[Common payload data|#common-payload-data]]]
"accessToken": "",
"verificationToken": "abc1234",
"userId": "1mEGCd1FvoAh",
"serverUrl": "https://mycompany.jetbrains.space",
"clientId": "2ulA3W2Vltg6",
"orgId": "8fd4d79a-d164-4a71-839a-ff8f8bcd6beb"
}
Payload types
To help you process different kinds of payload, Space SDK provides a number of classes. All these classes implement the ApplicationPayload
interface.
Class | Description | Relevant for |
---|
AppPublicationCheckPayload
| JetBrains Marketplace sends this payload during application verification. | Multi-org applications distributed through JetBrains Marketplace. |
ApplicationUninstalledPayload
| A Space instance sends this payload when the application is uninstalled from this instance. | Multi-org applications distributed via links or through JetBrains Marketplace. |
InitPayload
| Initializes the application that was installed from JetBrains Marketplace. | Multi-org applications distributed via links or through JetBrains Marketplace. |
ListCommandsPayload
| Requests a list of available commands. Space sends this payload type when a user types slash / or another character in the application chat channel. The application must respond with a JSON list of commands. | Chatbots, slash commands. |
MenuActionPayload
| Contains info about the custom menu item selected by a user. | Applications that extend Space context menus with custom items. |
MessagePayload
| Contains a message sent by a user to the application from a chat channel. | Chatbots, slash commands. |
MessageActionPayload
| Contains info about the action executed by a user in the application chat channel. Typically, this is a result of user interaction with a UI control in a chat message, for example, clicking a button. | Chatbots, slash commands. |
WebhookRequestPayload
| Contains info about the event occurred in Space. The application must be subscribed to this event with a corresponding webhook. | Applications that use webhooks to receive notifications about Space events. |
Reading the payload
To help you handle the payload, Space SDK provides the Space
helper object. This is how you can use it to process the payload depending on its type. For example, in a Ktor application:
@file:OptIn(ExperimentalSpaceSdkApi::class)
package com.example
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import space.jetbrains.api.ExperimentalSpaceSdkApi
import space.jetbrains.api.runtime.Space
import space.jetbrains.api.runtime.helpers.RequestAdapter
import space.jetbrains.api.runtime.helpers.SpaceHttpResponse
import space.jetbrains.api.runtime.helpers.processPayload
import space.jetbrains.api.runtime.ktorClientForSpace
import space.jetbrains.api.runtime.types.InitPayload
import space.jetbrains.api.runtime.types.MenuActionPayload
import space.jetbrains.api.runtime.types.RefreshTokenPayload
import space.jetbrains.api.runtime.SpaceAppInstance
import space.jetbrains.api.runtime.helpers.SpaceAppInstanceStorage
// we use in-memory storage for storing Space instances
// in real life, use a persistent storage, e.g., a database
val spaceInstances = HashMap<String, SpaceAppInstance>()
object AppInstanceStorage : SpaceAppInstanceStorage {
override suspend fun loadAppInstance(clientId: String): SpaceAppInstance? {
return spaceInstances[clientId]
}
override suspend fun saveAppInstance(appInstance: SpaceAppInstance) {
spaceInstances[appInstance.clientId] = appInstance
}
}
val ktorClient = ktorClientForSpace()
class KtorRequestAdapter(private val call: ApplicationCall) : RequestAdapter {
override suspend fun receiveText() = call.receiveText()
override fun getHeader(headerName: String) = call.request.headers[headerName]
override suspend fun respond(httpStatusCode: Int, body: String) {
call.respond(HttpStatusCode.fromValue(httpStatusCode), body)
}
}
fun Routing.routes() {
post("api/myapp") {
Space.processPayload(KtorRequestAdapter(call), ktorClient, AppInstanceStorage) { payload ->
// analyze payload type
when (payload) {
is InitPayload -> {
// initialize the app...
SpaceHttpResponse.RespondWithOk
}
is MenuActionPayload -> {
// react to menu item click
// val result = ...
SpaceHttpResponse.RespondWithResult(result)
}
is RefreshTokenPayload -> {
// save refresh token...
SpaceHttpResponse.RespondWithOk
}
else -> {
SpaceHttpResponse.RespondWithOk
}
}
}
}
}
In a more generic approach, you can use only the readPayload(body: String): ApplicationPayload
SDK helper function to handle payload:
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
post("/api/from-space") {
val body = call.receiveText()
val payload = readPayload(body)
// analyze payload type
when (payload) {
is MessagePayload -> {
println("This is MessagePayload")
call.respond(HttpStatusCode.OK, "")
}
else -> call.respond(HttpStatusCode.BadRequest,
"Unsupported payload type")
}
}
}
}.start(wait = true)
}
Common payload data
Regardless of the type, the payload that comes from Space always contains some common information: user ID, server URL, and other. To help you get this data, Space SDK provides a number of extension methods for the ApplicationPayload
interface.
val payload = readPayload(body)
// ID of a user who initiated the request
// Not available for the payload types that
// do not imply user interaction
val userId = payload.userId
// Client ID issued to the app
// during the [[[app registration|https://www.jetbrains.com.cn/en-us/help/space/register-app-in-space.html]]]
val clientId = payload.clientId
// URL of your Space instance
val url = payload.serverUrl
// ID of your organization in Space
val orgId = payload.orgId
// Verification token
// used to [[[verify Space in the app|https://www.jetbrains.com.cn/en-us/help/space/verify-requests-from-space.html]]]
// null if you choose other verification way
val token = payload.verificationToken
Last modified: 25 May 2023