Connection
Establish a secure gRPC connection to NextBlock's API using Node.js and @grpc/grpc-js.
Prerequisites
Install the required dependencies:
npm install @grpc/grpc-js @grpc/proto-loader
npm install @solana/web3.js
npm install typescript @types/node # For TypeScriptGenerate the gRPC client from proto specs:
# Clone the proto repository
git clone https://github.com/nextblock-ag/nextblock-proto
# Follow the JavaScript/TypeScript generation instructions in the repoConnection Setup
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { promisify } from 'util';
// Configuration interface
interface NextBlockConfig {
endpoint: string;
apiKey: string;
useTLS: boolean;
timeout: number;
keepaliveTimeMs: number;
keepaliveTimeoutMs: number;
}
// Default configuration
const defaultConfig: NextBlockConfig = {
endpoint: 'fra.nextblock.io:443',
apiKey: process.env.NEXTBLOCK_API_KEY || '',
useTLS: true,
timeout: 30000,
keepaliveTimeMs: 60000, // 60 seconds
keepaliveTimeoutMs: 15000, // 15 seconds
};
// Authentication metadata interceptor
class AuthInterceptor {
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
// Add authorization header to all requests
intercept(options: any, nextCall: any) {
return new grpc.InterceptingCall(nextCall(options), {
start: (metadata: grpc.Metadata, listener: any, next: any) => {
metadata.set('authorization', this.apiKey);
next(metadata, listener);
},
});
}
}
// Create gRPC channel with authentication
export async function createNextBlockChannel(config: NextBlockConfig): Promise<grpc.Channel> {
// Channel options for keepalive and performance
const channelOptions: grpc.ChannelOptions = {
'grpc.keepalive_time_ms': config.keepaliveTimeMs,
'grpc.keepalive_timeout_ms': config.keepaliveTimeoutMs,
'grpc.keepalive_permit_without_stream': 1,
'grpc.http2.max_pings_without_data': 0,
'grpc.http2.min_ping_interval_without_data_ms': 300000, // 5 minutes
};
// Create credentials
const credentials = config.useTLS
? grpc.credentials.createSsl()
: grpc.credentials.createInsecure();
// Create channel
const channel = new grpc.Channel(config.endpoint, credentials, channelOptions);
return channel;
}
// Create authenticated gRPC client
export async function createNextBlockClient(config: NextBlockConfig = defaultConfig) {
// Validate configuration
if (!config.apiKey) {
throw new Error('API key is required');
}
// Create channel
const channel = await createNextBlockChannel(config);
// Create authentication interceptor
const authInterceptor = new AuthInterceptor(config.apiKey);
// Load proto definition (replace with your generated client)
/* Example proto loading - replace with your actual proto
const packageDefinition = protoLoader.loadSync('path/to/your/nextblock.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition) as any;
const ApiClient = protoDescriptor.nextblock.Api;
// Create client with interceptor
const client = new ApiClient(config.endpoint, credentials, {
interceptors: [authInterceptor.intercept.bind(authInterceptor)],
...channelOptions,
});
*/
console.log(`Connected to NextBlock at ${config.endpoint}`);
return {
channel,
// client, // Uncomment when you have the generated client
config,
};
}
// Connection manager with health checking
export class NextBlockConnectionManager {
private config: NextBlockConfig;
private channel?: grpc.Channel;
private client?: any; // Replace with your generated client type
private isConnected: boolean = false;
constructor(config: NextBlockConfig = defaultConfig) {
this.config = config;
}
// Establish connection
async connect(): Promise<boolean> {
try {
const connection = await createNextBlockClient(this.config);
this.channel = connection.channel;
// this.client = connection.client;
// Test the connection
await this.healthCheck();
this.isConnected = true;
console.log(`Successfully connected to NextBlock at ${this.config.endpoint}`);
return true;
} catch (error) {
console.error('Failed to connect to NextBlock:', error);
this.isConnected = false;
return false;
}
}
// Health check
async healthCheck(): Promise<boolean> {
if (!this.channel) {
return false;
}
return new Promise((resolve) => {
// Check channel state
const state = this.channel!.getConnectivityState(false);
if (state === grpc.connectivityState.READY) {
console.log('Connection health check passed');
resolve(true);
} else {
console.log(`Connection state: ${grpc.connectivityState[state]}`);
resolve(false);
}
});
}
// Disconnect
async disconnect(): Promise<void> {
if (this.channel) {
this.channel.close();
this.isConnected = false;
console.log('Disconnected from NextBlock');
}
}
// Getters
get connected(): boolean {
return this.isConnected;
}
get grpcClient(): any {
return this.client;
}
}
// Configuration from environment variables
export function configFromEnv(): NextBlockConfig {
return {
endpoint: process.env.NEXTBLOCK_ENDPOINT || 'fra.nextblock.io:443',
apiKey: process.env.NEXTBLOCK_API_KEY || '',
useTLS: process.env.NEXTBLOCK_USE_TLS !== 'false',
timeout: parseInt(process.env.NEXTBLOCK_TIMEOUT || '30000'),
keepaliveTimeMs: parseInt(process.env.NEXTBLOCK_KEEPALIVE_TIME_MS || '60000'),
keepaliveTimeoutMs: parseInt(process.env.NEXTBLOCK_KEEPALIVE_TIMEOUT_MS || '15000'),
};
}Usage Examples
Available Endpoints
Frankfurt:
frankfurt.nextblock.io:443(Europe)Amsterdam:
amsterdam.nextblock.io:443(Europe)London:
london.nextblock.io:443(Europe)Singapore:
singapore.nextblock.io:443(Asia)Tokyo:
tokyo.nextblock.io:443(Asia)New York:
ny.nextblock.io:443(US East)Salt Lake City:
slc.nextblock.io:443(US West)Dublin:
dublin.nextblock.io:443(Europe)Vilnius:
vilnius.nextblock.io:443(Europe)
Best Practices
Use TypeScript: Leverage type safety for better development experience
Enable TLS: Always use secure connections in production
Implement keepalive: Configure appropriate keepalive settings for persistent connections
Handle errors gracefully: Use retry logic with exponential backoff
Validate configuration: Check all required settings before connecting
Use connection pooling: For high-throughput applications
Monitor connection health: Implement regular health checks
Environment variables: Store sensitive configuration securely
Close connections properly: Always close connections when done
Use interceptors: Implement authentication and logging via gRPC interceptors
Last updated