This page assumes you already have an authenticated client. Examples use the blocking client; async callers use the same builders and await terminal operations.
The fluent API works across create, update, and query flows. create_checked() tracks required fields in the builder type, so .send() is unavailable until all of them are supplied. Use create_raw and update_raw when values already exist as request structs.
let class = client
.classes()
.create_checked()
.name("example-class")
.collection_id(1)
.description("Example class")
.send()?;
let class = client.classes().get(42)?;
let class = client.classes().get_by_name("example-class")?;Resource identity is typed. Handles and resources expose IDs such as ClassId,
CollectionId, ObjectId, and GroupId, so accidentally passing a group ID to
classes().get(...) or objects(...) is rejected at compile time. Nested event,
history, template, and remote-target helpers use the same typed IDs. Integer
literals and raw i32 values still work through conversion into the expected ID
type, and an existing ID can be passed by value or by reference. Keep IDs typed
through application code and use .get() only at intentionally untyped or
polymorphic boundaries, such as a generic event entity ID.
Collections are the top-level organizational resource for classes, objects, export templates, imports, remote targets, and scoped permissions:
let collection = client
.collections()
.create_checked()
.name("platform")
.description("Platform inventory")
.group_id(admin_group_id)
.parent_collection_id(parent_collection_id)
.send()?;
let children = collection.children()?;
let ancestors = collection.ancestors()?;
let moved = collection.move_parent(new_parent_collection_id)?;
let effective = collection.effective_group_permissions(admin_group_id)?;Omit parent_collection_id(...) when creating a root collection. Permission helpers include direct grants plus effective inherited permission views for groups and principals.
Typed query fields expose only operators that make sense for that field shape:
let classes = client
.classes()
.name()
.contains("server")
.created_at()
.gte(since)
.limit(25)
.list()?;Filters compose by chaining field operators. Each operator appends another query condition and returns the query builder:
let classes = client
.classes()
.name()
.icontains("server")
.created_at()
.gte(since)
.validate_schema()
.eq(true)
.list()?;Scalar controls replace their previous value, so .limit(10).limit(25) sends
only limit=25. This applies to limits, cursors, sorting, and the typed event,
task, search, and rate-limit selectors; sort and order_by also replace each
other because they are aliases. Resource queries use raw_param() to append
repeated raw keys and set_raw_param() to replace a scalar key. Cursor and graph
requests provide the equivalent query_param() and set_query_param() methods.
Page limits and unified-search per-kind limits must be positive. The client
forwards every positive requested value unchanged; the server clamps it to the
effective max_page_limit advertised by the public client-config endpoint.
This keeps typed requests compatible with deployments whose configured maximum
is higher or lower than the server default.
Use list() for an unfiltered collection request:
let classes = client.classes().list()?;Use all() when you want the client to follow cursor pagination and collect all items. It stops at the configured page or item safety limit:
let classes = client.classes().limit(100).all()?;Use page() when you need cursor metadata. Page<T> exposes next_cursor, the
server's exact total_count when requested and returned, and convenience methods such as
len(), is_empty(), has_next(), iter(), and into_items(). It dereferences
to a slice for methods such as first() and can also be iterated directly:
let page = client.classes().limit(25).include_total(true).page()?;
println!("{} total matches", page.total_count.unwrap_or(page.len() as u64));
for class in page {
println!("{}", class.name);
}Paginated server endpoints compute an exact total by default. On latency-sensitive
requests that do not use the count, call include_total(false); the resulting
Page<T>::total_count will normally be None.
Event, history, task, import-result, and related-resource request builders also
support all(). Automatic pagination returns ApiError::PaginationCycle if a
server repeats a cursor instead of looping forever. The configured page and item
safety limits also apply to pages() and items(); use those methods for lazy
consumption without collecting the full result set.
Collection history has two source-compatible response surfaces. Existing
collection_history and collection_history_as_of calls return
CollectionHistory; use collection_history_full,
collection_history_as_of_full, or a collection handle's history_full when
the historical parent_collection_id is needed.
Existing QueryFilter values can be passed as a batch:
let classes = client
.classes()
.filters(vec![name_filter, collection_filter])
.list()?;Typed filters and raw filters can be mixed when an endpoint supports a query field that is not modeled yet:
let classes = client
.classes()
.name()
.contains("server")
.filter(
"collection_id",
hubuum_client::FilterOperator::Equals { is_negated: false },
42,
)
.list()?;Async clients use the same query builder and only await the terminal call:
let classes = client
.classes()
.name()
.contains("server")
.created_at()
.gte(since)
.list()
.await?;Use filter(...) or raw_param(...) for backend query features that are not modeled yet.
Find a relation between classes:
let relation = client
.class_relation()
.from_hubuum_class_id()
.eq(1)
.to_hubuum_class_id()
.eq(2)
.one()?;Related-object traversal follows the dedicated related/* endpoints, including graph fetches and endpoint-specific result filters:
let related = object
.related_objects()
.ignore_classes([42, 99])
.ignore_self_class(false)
.filter(
"from_classes",
hubuum_client::FilterOperator::Equals { is_negated: false },
42,
)
.limit(25)
.page()?;
let graph = object
.related_graph()
.filter(
"depth",
hubuum_client::FilterOperator::Equals { is_negated: false },
2,
)
.send()?;Grouped discovery searches are exposed through client.search(...):
let search = client
.search("server")
.kinds([
hubuum_client::UnifiedSearchKind::Collection,
hubuum_client::UnifiedSearchKind::Object,
])
.limit_per_kind(5)
.search_object_data(true)
.send()?;
for object in search.results.objects {
println!("{}", object.name);
}
let events = client
.search("server")
.kinds([hubuum_client::UnifiedSearchKind::Object])
.stream()?;
for event in events {
println!("{:?}", event?);
}HTTP errors include the request method, URL, status, parsed API message, and raw
body to make failed requests easier to diagnose. ApiError::status() returns the
HTTP status, and ApiError::api_response() parses the standard server
ApiErrorResponse payload when present. Login and health/readiness probe errors
use the same detailed representation as authenticated API calls.