Skip to main content

Deep dive: Building JSON RPC request methods

This deep dive explains how to use underlying primitives in the rpc-core library to construct RPC requests for any methods that aren't provided by SolanaRpcClient.

tip

If you only need to use the common RPC methods already supported by SolanaRpcClient, read the RPC Client usage guide.

Add dependencies

The rpc-core library provides core classes and abstractions to build and submit requests according to the JSON-RPC 2.0 specification.

dependencies {
  implementation("com.solanamobile:rpc-core:0.2.7")
}

Creating a JSON RPC Request

The rpc-core library defines a JsonRpc20Request constructor to conveniently construct a Solana JSON RPC request.

Populate the JSON object with the method name and JSON serialized parameters of a Solana RPC method. The constructor also includes a requestId parameter, as per JSON-RPC spec.

Example: getLatestBlockhash RPC request

fun createBlockhashRequest(commitment: String = "confirmed", requestId: String = "1") =
JsonRpc20Request(
// JSON RPC Method (ie: `getLatestBlockhash`, `getSignatureForAddresses`)
method = "getLatestBlockhash",
// Populate with JSON parameters
params = buildJsonArray {
addJsonObject {
put("commitment", commitment)
}
},
requestId
)

Defining the JSON RPC Response

After creating the request, create Kotlin serializable classes that define the expected response payload for that request.

In the following example, we are defining the expected response of the getLatestBlockhash request using the kotlinx.serialization library.

Example: getLatestBlockhash RPC response

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.*

@Serializable
class BlockhashResponse(val value: BlockhashInfo)

@Serializable
class BlockhashInfo(
val blockhash: String,
val lastValidBlockHeight: Long
)

// Additionally, define an exception in case of failure during request
class BlockhashException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)

Implement HttpNetworkDriver

The rpc-core library defines a HttpNetworkDriver interface that is used to make network requests.

interface HttpRequest {
val url: String
val method: String
val properties: Map<String, String>
val body: String?
}

interface HttpNetworkDriver {
suspend fun makeHttpRequest(request: HttpRequest): String
}

You can use a common networking package like the Ktor library to implement the makeHttpRequest method. The following is an example from the Kotlin Jetpack Compose Scaffold sample app.

import com.solana.networking.HttpNetworkDriver
import com.solana.networking.HttpRequest
import io.ktor.client.request.*
import io.ktor.client.HttpClient
import io.ktor.client.engine.android.Android
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpMethod

class KtorHttpDriver : HttpNetworkDriver {
override suspend fun makeHttpRequest(request: HttpRequest): String =
HttpClient(Android).use { client ->
client.request(request.url) {
method = HttpMethod.parse(request.method)
request.properties.forEach { (k, v) ->
header(k, v)
}
setBody(request.body)
}.bodyAsText()
}
}

Sending RPC requests

After putting these parts together, use the Rpc20Driver class to point to an RPC uri, send the request, and receive a response.

// import com.example.solanakotlincomposescaffold.networking.KtorHttpDriver
import com.solana.networking.Rpc20Driver
import com.solana.rpccore.JsonRpc20Request
import com.solana.transaction.Blockhash
import java.util.UUID

fun getLatestBlockhash(): Blockhash {
// Create the Rpc20Driver and specify the RPC uri and network driver
val rpc = Rpc20Driver("https://api.devnet.solana.com", KtorHttpDriver())

// Construct the RPC request
val requestId = UUID.randomUUID().toString()
val request = createBlockhashRequest(commitment, requestId)

// Send the request and provide the serializer for the expected response
val response = rpc.makeRequest(request, BlockhashResponse.serializer())

response.error?.let { error ->
throw BlockhashException("Could not fetch latest blockhash: ${error.code}, ${error.message}")
}

// Unwrap the response to receive the base58 blockhash string
val base58Blockhash = response.result?.value?.blockhash

// Return a `Blockhash` object from the web3-solana library
Blockhash.from(base58Blockhash
?: throw BlockhashException("Could not fetch latest blockhash: UnknownError"))
}

Next steps

  • Browse the full list of Solana RPC HTTP Methods