Learn by example - comprehensive code samples for every feature
Basic HTTP/1.1 request with automatic protocol negotiation
Make a simple GET request to any HTTPS endpoint:
#include "jvr/client.h"
#include <stdio.h>
int main() {
jvr_client_t* client = jvr_client_create();
jvr_request_t* req = jvr_request_create(
"GET", "https://api.github.com/users/github");
jvr_request_set_header(req, "User-Agent", "JVR/1.0");
jvr_response_t* res = jvr_client_send(client, req);
if (res && res->status_code == 200) {
printf("Success: %.*s\n",
(int)res->body_size, res->body);
}
jvr_response_destroy(res);
jvr_request_destroy(req);
jvr_client_destroy(client);
return 0;
}
Send JSON data to a REST API
POST JSON payload to an API endpoint:
#include "jvr/client.h"
int main() {
jvr_client_t* client = jvr_client_create();
const char* json = "{\"name\":\"John\",\"age\":30}";
jvr_request_t* req = jvr_request_create(
"POST", "https://api.example.com/users");
jvr_request_set_header(req, "Content-Type",
"application/json");
jvr_request_set_body(req, json, strlen(json));
jvr_response_t* res = jvr_client_send(client, req);
printf("Status: %d\n", res->status_code);
jvr_response_destroy(res);
jvr_request_destroy(req);
jvr_client_destroy(client);
return 0;
}
Multiple concurrent requests over one connection
Send multiple requests simultaneously:
#include "jvr/client.h"
int main() {
jvr_client_config_t config = {
.prefer_http2 = true,
.max_concurrent_streams = 100
};
jvr_client_t* client =
jvr_client_create_with_config(&config);
jvr_request_t* req1 = jvr_request_create(
"GET", "https://example.com/api/users");
jvr_request_t* req2 = jvr_request_create(
"GET", "https://example.com/api/posts");
jvr_request_t* req3 = jvr_request_create(
"GET", "https://example.com/api/comments");
// All three use the same connection!
jvr_response_t* res1 = jvr_client_send(client, req1);
jvr_response_t* res2 = jvr_client_send(client, req2);
jvr_response_t* res3 = jvr_client_send(client, req3);
// Process responses...
return 0;
}
Ultra-fast HTTP/3 requests
Use HTTP/3 for maximum performance:
#include "jvr/client.h"
int main() {
jvr_client_config_t config = {
.prefer_http3 = true
};
jvr_client_t* client =
jvr_client_create_with_config(&config);
jvr_request_t* req = jvr_request_create(
"GET", "https://cloudflare.com");
jvr_response_t* res = jvr_client_send(client, req);
printf("Protocol: HTTP/3 over QUIC\n");
printf("Status: %d\n", res->status_code);
jvr_response_destroy(res);
jvr_request_destroy(req);
jvr_client_destroy(client);
return 0;
}
Switch networks without dropping connection
Seamlessly migrate between WiFi and cellular:
#include "jvr/quic_advanced.h"
int main() {
jvr_quic_connection_t* conn =
jvr_quic_connection_create(&config);
// Enable migration
jvr_quic_enable_migration(conn);
jvr_quic_connect(conn);
// Use connection...
// Network changed? Migrate!
if (network_switched_to_cellular) {
jvr_quic_migrate_connection(conn,
cellular_ip, 443);
// Connection continues seamlessly!
}
jvr_quic_migration_state_t state;
jvr_quic_get_migration_state(conn, &state);
if (state.status == JVR_QUIC_MIGRATION_COMPLETED) {
printf("Migrated successfully!\n");
}
return 0;
}
50% faster reconnections with 0-RTT
Resume connections instantly:
#include "jvr/quic_advanced.h"
// First connection - save session
jvr_quic_connection_t* conn =
jvr_quic_connection_create(&config);
jvr_quic_enable_0rtt(conn);
jvr_quic_connect(conn);
uint8_t* ticket;
size_t ticket_len;
jvr_quic_save_session(conn, &ticket, &ticket_len);
// Store ticket to disk/database...
jvr_quic_close(conn, 0, "done");
// Later: Fast reconnect with 0-RTT!
jvr_quic_connection_t* new_conn =
jvr_quic_connection_create(&config);
jvr_quic_enable_0rtt(new_conn);
jvr_quic_restore_session(new_conn, ticket, ticket_len);
// Send data BEFORE handshake completes!
jvr_quic_send_early_data(new_conn, "GET /api/data", 13);
if (jvr_quic_is_0rtt_accepted(new_conn)) {
printf("0-RTT accepted - super fast!\n");
}
Real-time bidirectional communication
Build real-time applications:
#include "jvr/websocket.h"
void on_message(jvr_websocket_t* ws,
const char* data, size_t len,
bool is_binary) {
printf("Received: %.*s\n", (int)len, data);
}
void on_open(jvr_websocket_t* ws) {
printf("Connected!\n");
jvr_websocket_send_text(ws, "Hello!");
}
int main() {
jvr_websocket_t* ws = jvr_websocket_create(
"wss://echo.websocket.org");
jvr_websocket_set_on_open(ws, on_open);
jvr_websocket_set_on_message(ws, on_message);
jvr_websocket_connect(ws);
// Send messages
jvr_websocket_send_text(ws, "Hello Server!");
return 0;
}
Prevent cascading failures
Build resilient applications:
#include "jvr/circuit_breaker.h"
jvr_circuit_breaker_config_t config = {
.failure_threshold = 5,
.timeout_ms = 60000,
.success_threshold = 2
};
jvr_circuit_breaker_t* cb =
jvr_circuit_breaker_create(&config);
// Use circuit breaker
if (jvr_circuit_breaker_allow_request(cb)) {
jvr_response_t* res = make_api_call();
if (res && res->status_code == 200) {
jvr_circuit_breaker_record_success(cb);
} else {
jvr_circuit_breaker_record_failure(cb);
}
} else {
printf("Circuit OPEN - request rejected!\n");
}
Composable request/response processing
Chain multiple middlewares:
#include "jvr/middleware.h"
jvr_middleware_pipeline_t* pipeline =
jvr_middleware_pipeline_create();
// Add middlewares
jvr_middleware_pipeline_add(pipeline,
jvr_middleware_logger_create());
jvr_middleware_pipeline_add(pipeline,
jvr_middleware_auth_create("Bearer", token));
jvr_middleware_pipeline_add(pipeline,
jvr_middleware_compression_create());
// Use with client
jvr_client_t* client = jvr_client_create();
jvr_client_set_middleware(client, pipeline);
// All requests go through the pipeline!
jvr_response_t* res = jvr_client_send(client, req);
HTTP-compliant response caching
Cache responses for better performance:
#include "jvr/response_cache.h"
// Create cache (10 MB, 1000 entries)
jvr_response_cache_t* cache =
jvr_response_cache_create(
10 * 1024 * 1024, 1000);
jvr_client_t* client = jvr_client_create();
jvr_client_set_cache(client, cache);
// First request - MISS
jvr_response_t* res1 =
jvr_client_send(client, req);
// Second request - HIT!
jvr_response_t* res2 =
jvr_client_send(client, req);
jvr_cache_stats_t stats;
jvr_response_cache_get_stats(cache, &stats);
printf("Hit rate: %.2f%%\n", stats.hit_rate * 100);
Built-in production metrics
Track everything automatically:
#include "jvr/metrics.h"
jvr_metrics_registry_t* metrics =
jvr_metrics_get_global();
// Track request
jvr_request_tracker_t* tracker =
jvr_metrics_track_request(metrics,
"GET", "/api/users");
// ... handle request ...
// Auto-records latency and status
jvr_metrics_complete_request(tracker, 200);
// Get stats
jvr_http_metrics_t stats;
jvr_metrics_get_http(metrics, &stats);
printf("Requests: %llu\n", stats.total_requests);
// Export to Prometheus
char* prom_text;
size_t prom_size;
jvr_metrics_export_prometheus(metrics,
&prom_text, &prom_size);
All features combined
Production-ready example with all features:
#include "jvr/client.h"
#include "jvr/middleware.h"
#include "jvr/circuit_breaker.h"
#include "jvr/response_cache.h"
#include "jvr/metrics.h"
int main() {
// Configure client
jvr_client_config_t config = {
.prefer_http3 = true,
.prefer_http2 = true
};
jvr_client_t* client =
jvr_client_create_with_config(&config);
// Add middleware
jvr_middleware_pipeline_t* pipeline =
jvr_middleware_pipeline_create();
jvr_middleware_pipeline_add(pipeline,
jvr_middleware_logger_create());
jvr_client_set_middleware(client, pipeline);
// Add cache
jvr_response_cache_t* cache =
jvr_response_cache_create(10*1024*1024, 1000);
jvr_client_set_cache(client, cache);
// Circuit breaker
jvr_circuit_breaker_t* cb =
jvr_circuit_breaker_create(&cb_config);
// Track metrics
jvr_metrics_registry_t* metrics =
jvr_metrics_get_global();
// Make request
if (jvr_circuit_breaker_allow_request(cb)) {
jvr_request_tracker_t* tracker =
jvr_metrics_track_request(metrics,
"GET", "/api/data");
jvr_request_t* req = jvr_request_create(
"GET", "https://api.example.com/data");
jvr_response_t* res =
jvr_client_send(client, req);
if (res && res->status_code == 200) {
jvr_circuit_breaker_record_success(cb);
jvr_metrics_complete_request(tracker, 200);
}
}
return 0;
}