vectrixdb
The Rust client for VectrixDB: collections, documents, text search and
sources, over the server's HTTP API. It offers the same calls as the other
VectrixDB clients, spelled in snake_case, and is built from docs/reference/openapi.json.
Install
Add it to Cargo.toml:
[]
= "2.2"
= { = "1", = ["macros", "rt-multi-thread"] }
The client is async and runs on tokio. TLS comes from rustls; no OpenSSL is needed.
Quickstart
use ;
async
Client::new(url) returns a builder: .key(..) sends an API key in the
api-key header, .token(..) sends a company sign-in token as
Authorization: Bearer, .timeout(..) sets the per-request timeout (30 s by
default), and .build() makes the client. A key or token is never sent over
plain http:// to a host other than this machine (localhost, 127.0.0.0/8,
::1): build() refuses unless .allow_http(true) is set. The client never
follows a redirect, since the key would go with it; a 3xx is an
Error::Api of kind Other naming the status and the location. A 429 or 503 is retried up to three
times, waiting the server's Retry-After when it sends one, else 1 s, 2 s,
4 s. Every request carries user-agent: vectrixdb-rust/2.2.0.
Each result struct (Collection, Hit, Document, Added, Source,
Refreshed) names the fields the contract promises and keeps everything else
the server sent in extra. A Hit has a citation: _vx_citation from the
metadata, else source, else the id.
Behind a company gateway
The builder has what a company's gateway, proxy and private CA ask for, the same options as the other VectrixDB clients:
let db = new
.token
.token_header // default `authorization`, always `Bearer <token>`
.header // sent on every request
.prefix
.gateway_paths
.ca_certificate
.identity
.build?;
.key_header(name)(defaultapi-key) and.token_header(name)(defaultauthorization) name the headers the key and token go in. The server'sVECTRIXDB_KEY_HEADERandVECTRIXDB_TOKEN_HEADERare the same settings..header(name, value)adds a header to every request. It never replacesuser-agentor the key or token header..prefix(p)and.gateway_paths(list): a request for a route goes to<gateway path><prefix><route>, the gateway path being that of the longest name the route falls under, so/api/v1/collectionsabove goes to/files/search/acme/api/v1/collectionsand/healthto/acme/health. The list is text or a map (HashMap,BTreeMap, or(name, path)pairs), read as the server reads itsVECTRIXDB_GATEWAY_PATHS: slashes trimmed, doubled ones dropped,.and.., an empty side or a name given twice refused..ca_certificate(pem)trusts a private CA (a PEM certificate or bundle) as well as the usual roots;.identity(pem)gives a client certificate (the certificate and its private key in one PEM). Certificates are always checked; there is no option to turn that off.HTTPS_PROXY,HTTP_PROXYandNO_PROXYare honoured.
Every setting is checked by build(), which says what is wrong as an
Error::Transport: among them a key, token or header value with a control
character, and an address with a user name or password in it
(https://user:pw@host), neither repeated in the message. The key and token
never appear in an error message or in the Debug form of the builder or the
client. A collection name, document id or source id is sent as one path
segment (/ as %2F); an empty one, . or .. is refused with an
Error::Transport before anything is sent.
The calls
| Call | What it does |
|---|---|
health(), ready() |
the process answers; the models are loaded |
whoami() |
who the key or token is |
collections(), describe(name), create_collection(name, CreateOptions), delete_collection(name) |
collections |
add_document(collection, bytes, filename, AddOptions) |
upload a file; the server extracts, chunks and embeds it |
add_texts(collection, Vec<Text>) |
embed and store texts; returns how many were added |
search(collection, query, SearchOptions) |
Mode::Meaning (dense) or Mode::Hybrid, with limit, filter, rerank |
documents(collection), open_document(collection, doc_id), delete_document(collection, doc_id) |
the kept documents |
sources(collection), add_source(collection, address, SourceOptions), refresh_sources(collection), delete_source(collection, id, delete_documents) |
feeds and pages |
Blocking
With the blocking feature, Client::new(url).key(..).build_blocking() gives
a BlockingClient with the same calls, each one synchronous. It drives the
async client on a runtime of its own, so call it from plain threads, not from
inside another async runtime.
= { = "2.2", = ["blocking"] }
Errors
Every call returns vectrixdb::Result<T>. The server's refusals are
Error::Api { status, kind, message, detail }; a server that cannot be reached
is Error::Transport, and a request that outlives the timeout is
Error::Timeout. kind is one of:
| Status | Kind |
Helper |
|---|---|---|
| 401 | Auth (no key, or a wrong one) |
is_auth() |
| 403 | Forbidden (the key's role or scope says no) |
is_forbidden() |
| 404 | NotFound |
is_not_found() |
| 409 | Conflict |
is_conflict() |
| 413 | TooLarge |
is_too_large() |
| 422 | Invalid (detail is the field list) |
is_invalid() |
| 429, 503 after the retries | Busy |
is_busy() |
| any other 4xx or 5xx | Other |
A message the server did not send (an HTML page from a proxy) is replaced
with "<status> from <url>".
Generated request types
src/generated.rs holds the request bodies, generated from docs/reference/openapi.json
by scripts/generate.py. After the spec changes, run
python3 -I scripts/generate.py from this directory. A unit test checks that
every route and body field the client uses is in the spec.
Tests
The conformance test reads VECTRIXDB_URL and VECTRIXDB_KEY. When they are
unset it starts sdk/conformance/serve.py itself with the interpreter named
by PYTHON (default python3), which needs the vectrixdb[api] package
installed, and stops it at the end.
Cargo.lock is committed so CI builds are reproducible.
Examples
VECTRIXDB_TOKEN=...