Connection
Establish a connection to NextBlock's gRPC API using Tonic. You can configure both secure (TLS) and insecure connections.
Prerequisites
Add these dependencies to your Cargo.toml
:
[dependencies]
tonic = "0.10"
tokio = { version = "1.0", features = ["full"] }
solana-sdk = "1.17"
solana-client = "1.17"
base64 = "0.21"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rand = "0.8"
# Add your generated proto dependencies here
# nextblock-proto = { path = "./generated" }
Connection Setup
use std::time::Duration;
use tonic::{
transport::{Channel, ClientTlsConfig, Endpoint},
metadata::{MetadataValue, MetadataMap},
Request, Status,
};
use tokio::time;
// Authentication interceptor for API key
#[derive(Clone)]
pub struct AuthInterceptor {
api_key: MetadataValue<tonic::metadata::Ascii>,
}
impl AuthInterceptor {
pub fn new(api_key: String) -> Result<Self, tonic::metadata::errors::InvalidMetadataValue> {
let api_key = MetadataValue::try_from(api_key)?;
Ok(Self { api_key })
}
}
impl tonic::service::Interceptor for AuthInterceptor {
fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, Status> {
request.metadata_mut().insert("authorization", self.api_key.clone());
Ok(request)
}
}
// Connection configuration
pub struct NextBlockConfig {
pub endpoint: String,
pub api_key: String,
pub use_tls: bool,
pub timeout: Duration,
}
impl Default for NextBlockConfig {
fn default() -> Self {
Self {
endpoint: "https://fra.nextblock.io".to_string(),
api_key: String::new(),
use_tls: true,
timeout: Duration::from_secs(30),
}
}
}
// Establish connection to NextBlock
pub async fn connect_to_nextblock(config: NextBlockConfig) -> Result<Channel, Box<dyn std::error::Error>> {
let mut endpoint = Endpoint::from_shared(config.endpoint)?
.timeout(config.timeout)
.tcp_keepalive(Some(Duration::from_secs(60)))
.http2_keep_alive_interval(Some(Duration::from_secs(30)))
.keep_alive_timeout(Duration::from_secs(15))
.keep_alive_while_idle(true);
// Configure TLS if enabled
if config.use_tls {
let tls_config = ClientTlsConfig::new()
.with_native_roots();
endpoint = endpoint.tls_config(tls_config)?;
}
// Create the channel
let channel = endpoint.connect().await?;
Ok(channel)
}
// Create authenticated client
pub async fn create_nextblock_client(
config: NextBlockConfig,
) -> Result</* YourGeneratedClient */(), Box<dyn std::error::Error>> {
let channel = connect_to_nextblock(config.clone()).await?;
// Create authentication interceptor
let auth_interceptor = AuthInterceptor::new(config.api_key)?;
// Create the client with authentication
// let client = YourGeneratedApiClient::with_interceptor(channel, auth_interceptor);
// Return the client
// Ok(client)
Ok(())
}
Usage Example
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Configure connection
let config = NextBlockConfig {
endpoint: "https://fra.nextblock.io".to_string(),
api_key: "<your-api-key-here>".to_string(),
use_tls: true,
timeout: Duration::from_secs(30),
};
// Create authenticated client
let client = create_nextblock_client(config).await?;
// Use the client for API calls
// See other examples for specific usage patterns
println!("Successfully connected to NextBlock!");
Ok(())
}
Connection Best Practices
Use TLS in production: Always enable TLS for production environments
Configure keepalive: HTTP/2 keepalive helps maintain persistent connections
Set appropriate timeouts: Configure timeouts based on your use case
Handle authentication: Use the interceptor pattern for API key authentication
Error handling: Implement proper error handling and retry logic
Available Endpoints
Frankfurt:
https://fra.nextblock.io
(Europe)New York:
https://ny.nextblock.io
(US East)Direct NY:
https://direct-ny.nextblock.io
(US East, optimized routing)
Environment Configuration
use std::env;
pub fn config_from_env() -> NextBlockConfig {
NextBlockConfig {
endpoint: env::var("NEXTBLOCK_ENDPOINT")
.unwrap_or_else(|_| "https://fra.nextblock.io".to_string()),
api_key: env::var("NEXTBLOCK_API_KEY")
.expect("NEXTBLOCK_API_KEY must be set"),
use_tls: env::var("NEXTBLOCK_USE_TLS")
.map(|v| v.to_lowercase() == "true")
.unwrap_or(true),
timeout: Duration::from_secs(
env::var("NEXTBLOCK_TIMEOUT")
.and_then(|v| v.parse().ok())
.unwrap_or(30)
),
}
}
Last updated