C/C++ SDK
Native C library with C++ wrapper for InferaDB.
Coming soon. The C/C++ SDK is under active development. The API surface shown here is based on the Rust SDK and may change before release.
Native client for InferaDB’s authorization APIs. The C library (inferadb.h) offers a stable ABI suitable for FFI. The C++ wrapper (inferadb.hpp) adds RAII and C++20 idioms. Built on the Rust SDK via cxx for memory safety in the transport layer.
Requires C11 (C API) or C++20 (C++ wrapper).
Installation
vcpkg
vcpkg install inferadb
CMake (FetchContent)
include(FetchContent)
FetchContent_Declare(
inferadb
GIT_REPOSITORY https://github.com/inferadb/c.git
GIT_TAG v0.1.0
)
FetchContent_MakeAvailable(inferadb)
target_link_libraries(my_app PRIVATE inferadb::inferadb)
pkg-config (system install)
pkg-config --cflags --libs inferadb
C API
Client Initialization
#include <inferadb.h>
inferadb_client_t *client = NULL;
inferadb_error_t *err = NULL;
inferadb_config_t config = {
.url = "https://engine.inferadb.com",
.auth = {
.type = INFERADB_AUTH_CLIENT_CREDENTIALS,
.client_credentials = {
.client_id = "my-client",
.private_key_path = "client.pem",
.certificate_id = "cert-id",
},
},
};
if (inferadb_client_new(&config, &client, &err) != INFERADB_OK) {
fprintf(stderr, "Failed to connect: %s\n", inferadb_error_message(err));
inferadb_error_free(err);
return 1;
}
/* ... use client ... */
inferadb_client_free(client);
Permission Checks
inferadb_vault_t *vault = inferadb_vault_open(client, "my-org", "production", &err);
bool allowed = false;
if (inferadb_check(vault, "user:alice", "can_edit", "document:readme",
NULL, &allowed, &err) != INFERADB_OK) {
fprintf(stderr, "Check failed: %s\n", inferadb_error_message(err));
inferadb_error_free(err);
}
if (allowed) {
/* access granted */
}
inferadb_vault_free(vault);
With ABAC Context
inferadb_context_t *ctx = inferadb_context_new();
inferadb_context_set_string(ctx, "ip_address", "10.0.0.1");
bool allowed = false;
inferadb_check(vault, "user:alice", "can_view", "document:readme",
ctx, &allowed, &err);
inferadb_context_free(ctx);
Batch Check
inferadb_check_request_t requests[] = {
{ .subject = "user:alice", .permission = "can_edit", .resource = "document:readme" },
{ .subject = "user:bob", .permission = "can_view", .resource = "document:readme" },
};
inferadb_check_result_t *results = NULL;
size_t result_count = 0;
if (inferadb_check_batch(vault, requests, 2, &results, &result_count, &err) != INFERADB_OK) {
fprintf(stderr, "Batch check failed: %s\n", inferadb_error_message(err));
inferadb_error_free(err);
}
for (size_t i = 0; i < result_count; i++) {
printf("Request %zu: %s\n", i, results[i].allowed ? "allowed" : "denied");
}
inferadb_check_results_free(results, result_count);
Relationships
/* Write */
inferadb_revision_t *token = NULL;
inferadb_write_relationship(vault,
"document:readme", "editor", "user:alice",
&token, &err);
inferadb_revision_free(token);
/* Delete */
inferadb_delete_relationship(vault,
"document:readme", "viewer", "user:bob",
&err);
Error Handling
inferadb_error_t *err = NULL;
bool allowed = false;
if (inferadb_check(vault, "user:alice", "can_edit", "document:readme",
NULL, &allowed, &err) != INFERADB_OK) {
inferadb_error_kind_t kind = inferadb_error_kind(err);
if (inferadb_error_is_retriable(err)) {
unsigned int retry_after_ms = inferadb_error_retry_after(err);
/* retry after delay */
}
inferadb_error_free(err);
}
Error kinds: INFERADB_ERR_UNAUTHORIZED, INFERADB_ERR_FORBIDDEN, INFERADB_ERR_NOT_FOUND, INFERADB_ERR_RATE_LIMITED, INFERADB_ERR_SCHEMA_VIOLATION, INFERADB_ERR_UNAVAILABLE, INFERADB_ERR_TIMEOUT, INFERADB_ERR_INVALID_ARGUMENT.
Cleanup
Every _new/_open has a corresponding _free. Every output parameter that allocates must be freed by the caller.
| Allocator | Deallocator |
|---|---|
inferadb_client_new |
inferadb_client_free |
inferadb_vault_open |
inferadb_vault_free |
inferadb_context_new |
inferadb_context_free |
inferadb_revision_* (output) |
inferadb_revision_free |
inferadb_check_batch (output) |
inferadb_check_results_free |
inferadb_error_* (output) |
inferadb_error_free |
C++ API
RAII resource management, exceptions, and modern C++20 idioms:
Client Initialization
#include <inferadb/inferadb.hpp>
auto client = inferadb::Client::builder()
.url("https://engine.inferadb.com")
.credentials(inferadb::ClientCredentials{
.client_id = "my-client",
.private_key = inferadb::Ed25519PrivateKey::from_pem_file("client.pem"),
.certificate_id = "cert-id",
})
.build();
Permission Checks
auto vault = client.organization("my-org").vault("production");
// Simple check
bool allowed = vault.check("user:alice", "can_edit", "document:readme");
// With ABAC context
auto opts = inferadb::CheckOptions{};
opts.context["ip_address"] = "10.0.0.1";
bool allowed = vault.check("user:alice", "can_view", "document:readme", opts);
// Require — throws inferadb::AccessDeniedError
vault.require("user:alice", "can_edit", "document:readme");
// Batch check
auto results = vault.check_batch({
{"user:alice", "can_edit", "document:readme"},
{"user:bob", "can_view", "document:readme"},
});
if (results.all_allowed()) {
// all checks passed
}
Relationships
// Write — returns a revision token
auto token = vault.relationships().write({
.resource = "document:readme",
.relation = "editor",
.subject = "user:alice",
});
// Batch write
vault.relationships().write_batch({
{"document:readme", "editor", "user:alice"},
{"document:readme", "viewer", "user:bob"},
});
// List
auto rels = vault.relationships().list({.resource = "document:readme"});
// Delete
vault.relationships().delete_where({
.resource = "document:readme",
.relation = "viewer",
.subject = "user:bob",
});
Error Handling
#include <inferadb/inferadb.hpp>
try {
vault.require("user:alice", "can_edit", "document:readme");
} catch (const inferadb::AccessDeniedError&) {
// permission denied
} catch (const inferadb::Error& e) {
if (e.is_retriable()) {
std::this_thread::sleep_for(e.retry_after());
// retry
}
std::cerr << "Error: kind=" << e.kind_name()
<< " request_id=" << e.request_id() << "\n";
}
RAII Guarantees
inferadb::Client— move-only, closes connection on destructioninferadb::Vault— lightweight handle, safe to copyinferadb::Revision— copyable, movable, comparable
Testing
MockClient
#include <inferadb/testing.hpp>
auto client = inferadb::testing::MockClient::builder()
.on_check("user:alice", "can_edit", "document:readme").allow()
.on_check("user:bob", "can_edit", "document:readme").deny()
.on_check_any_subject("can_view", "document:readme").allow()
.default_deny()
.verify_on_destroy(true)
.build();
InMemoryClient
auto client = inferadb::testing::InMemoryClient::with_schema_and_data(
R"(
type document {
relation viewer
relation editor
relation can_view = viewer | editor
}
)",
{
{"document:readme", "editor", "user:alice"},
{"document:readme", "viewer", "user:bob"},
}
);
Thread Safety
inferadb::Clientandinferadb::Vaultare thread-safe and shareable- C API is thread-safe with per-thread
inferadb_vault_t*or external synchronization - All
inferadb_*_freecalls are safe from any thread
Platform Support
| Platform | Architecture | Status |
|---|---|---|
| Linux | x86_64, aarch64 | Supported |
| macOS | x86_64, arm64 | Supported |
| Windows | x86_64 | Supported |
| FreeBSD | x86_64 | Best-effort |
Prebuilt binaries are available for all supported platforms via the GitHub releases page and vcpkg.