Receive Payload from SpaceCode
With some types of applications, SpaceCode 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, SpaceCode sends payload containing the user input; if the application is subscribed to webhook notifications, SpaceCode 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 SpaceCode URL, user ID, and so on).
For example, this is a sample payload from SpaceCode 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, SpaceCode 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 SpaceCode 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. |
Chat Messages | Requests a list of available commands. SpaceCode 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. |
Chat Messages | Contains a message sent by a user to the application from a chat channel. | Chatbots, slash commands. |
Chat Messages | 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 SpaceCode. The application must be subscribed to this event with a corresponding webhook. | Applications that use webhooks to receive notifications about SpaceCode events. |
Reading the payload
To help you handle the payload, SpaceCode SDK provides the SpaceCode 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(ExperimentalSpaceCodeSdkApi::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.ExperimentalSpaceCodeSdkApi
import space.jetbrains.api.runtime.SpaceCode
import space.jetbrains.api.runtime.helpers.RequestAdapter
import space.jetbrains.api.runtime.helpers.SpaceCodeHttpResponse
import space.jetbrains.api.runtime.helpers.processPayload
import space.jetbrains.api.runtime.ktorClientForSpaceCode
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.SpaceCodeAppInstance
import space.jetbrains.api.runtime.helpers.SpaceCodeAppInstanceStorage
// we use in-memory storage for storing SpaceCode instances
// in real life, use a persistent storage, e.g., a database
val spaceInstances = HashMap<String, SpaceCodeAppInstance>()
object AppInstanceStorage : SpaceCodeAppInstanceStorage {
override suspend fun loadAppInstance(clientId: String): SpaceCodeAppInstance? {
return spaceInstances[clientId]
}
override suspend fun saveAppInstance(appInstance: SpaceCodeAppInstance) {
spaceInstances[appInstance.clientId] = appInstance
}
}
val ktorClient = ktorClientForSpaceCode()
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") {
SpaceCode.processPayload(KtorRequestAdapter(call), ktorClient, AppInstanceStorage) { payload ->
// analyze payload type
when (payload) {
is InitPayload -> {
// initialize the app...
SpaceCodeHttpResponse.RespondWithOk
}
is MenuActionPayload -> {
// react to menu item click
// val result = ...
SpaceCodeHttpResponse.RespondWithResult(result)
}
is RefreshTokenPayload -> {
// save refresh token...
SpaceCodeHttpResponse.RespondWithOk
}
else -> {
SpaceCodeHttpResponse.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 SpaceCode always contains some common information: user ID, server URL, and other. To help you get this data, SpaceCode 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/help/space/register-app-in-space.html]]]
val clientId = payload.clientId
// URL of your SpaceCode instance
val url = payload.serverUrl
// ID of your organization in SpaceCode
val orgId = payload.orgId
// Verification token
// used to [[[verify SpaceCode in the app|https://www.jetbrains.com/help/space/verify-requests-from-space.html]]]
// null if you choose other verification way
val token = payload.verificationToken
Last modified: 23 April 2024