LioranDB TypeScript Series #3: Connection Strings, Transports and Client Lifecycle
LioranDB TypeScript Series: Build with a developer-first document database powered by Rust and designed for TypeScript.
We connected to LioranDB in Part 2 with one line:
const client = await LioranDBClient.connect(process.env.URI!);
Enter fullscreen mode Exit fullscreen mode
There’s quite a bit happening underneath it.
Let’s unpack it.
Connection URI
A typical local URI looks like:
liorandb://admin:[email protected]:27018/default
Enter fullscreen mode Exit fullscreen mode
Conceptually:
liorandb:// USER : PASSWORD @ HOST : PORT / DATABASE
Enter fullscreen mode Exit fullscreen mode
LioranDB understands multiple schemes:
liorandb://
liorandb+http://
liorandb+https://
http://
https://
grpc://
Enter fullscreen mode Exit fullscreen mode
For example:
liorandb://admin:[email protected]:27018/default
Enter fullscreen mode Exit fullscreen mode
or:
liorandb+https://admin:[email protected]/default
Enter fullscreen mode Exit fullscreen mode
Reserved characters matter
Suppose your password is:
hello@database#123
Enter fullscreen mode Exit fullscreen mode
Don’t place that directly inside the URI.
Encode it:
const password = encodeURIComponent("hello@database#123");
const uri =
`liorandb://admin:${password}@127.0.0.1:27018/default`;
Enter fullscreen mode Exit fullscreen mode
This avoids the URI parser interpreting password characters as URI syntax.
Parsing connection strings
The driver exposes its parser:
import { parseConnectionString } from "@liorandb/driver";
const config = parseConnectionString(
"liorandb://admin:[email protected]:27018/default"
);
console.log(config);
Enter fullscreen mode Exit fullscreen mode
This is useful for tooling, debugging and infrastructure layers that need to inspect connection configuration.
Client options
You can also configure the client explicitly.
const client = await LioranDBClient.connect(uri, {
transport: "auto",
autoRefreshTokens: true,
logoutOnClose: true,
requestTimeoutMS: 5000,
slowRequestThresholdMS: 200,
onWarning(warning) {
console.warn(
`[${warning.code}] ${warning.message}`
);
},
});
Enter fullscreen mode Exit fullscreen mode
Important options include:
transporttimeoutMSconnectTimeoutMSrequestTimeoutMSgrpcChannelsmaxRetriesretryDelayMSautoRefreshTokenslogoutOnCloseappNameslowRequestThresholdMSonWarning
For most applications, transport: "auto" is the sensible starting point.
Diagnostics
You can attach diagnostic headers:
client.setDiagnosticHeaders({
"x-trace-id": "request-001",
});
Enter fullscreen mode Exit fullscreen mode
And observe responses:
client.setResponseObserver((event) => {
console.log({
transport: event.transport,
operation: event.operation,
durationMS: event.durationMS,
requestId: event.requestId,
});
});
Enter fullscreen mode Exit fullscreen mode
This becomes especially useful when debugging latency or transport behavior.
Health and discovery
The client also provides helpers for inspecting the server:
await client.live();
await client.ready();
await client.serverInfo();
await client.listDatabases();
Enter fullscreen mode Exit fullscreen mode
Client lifecycle
A good application lifecycle looks like this:
const client = await LioranDBClient.connect(uri);
try {
const db = client.db("default");
// application work
} finally {
await client.close();
}
Enter fullscreen mode Exit fullscreen mode
Closing the client cleans up its resources, transports and cursors.
Attempting to use a closed client results in ClientClosedError.
One client, many collections
Don’t create a new database connection for every query.
Create the client at the appropriate application lifecycle boundary and reuse it.
Application
↓
LioranDBClient
├── users
├── products
├── sessions
└── events
Enter fullscreen mode Exit fullscreen mode
That’s both cleaner and considerably closer to how a database client is intended to be used.
Resources
Connection & Client Docs:
https://docs.liorandb.com/docs/driver/connection-and-client
Documentation: https://docs.liorandb.com
Website: https://liorandb.com
Creator: https://github.com/UltronTheAI
Previous: Part 2 → Docker & First Query
Next: Part 4 → Databases, Collections & Typed CRUD
Enter fullscreen mode Exit fullscreen mode