labkey-rs 0.2.1

Unofficial Rust client for the LabKey Server REST API
docs.rs failed to build labkey-rs-0.2.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: labkey-rs-0.1.0

labkey-rs

crates.io docs.rs

Unofficial Rust client for the LabKey Server REST API.

[!IMPORTANT] This is a third-party client maintained by the community, not by LabKey Corporation. It is unofficial, not supported by LabKey, and currently maintained outside the official LabKey client suite.

This crate provides typed, async access to LabKey's HTTP endpoints for querying data, managing security, working with assays and experiments, and more. It is a port of the official @labkey/api JavaScript/TypeScript client (v1.48.0), supplemented by the Java client for endpoint coverage. It is not affiliated with or endorsed by LabKey Corporation.

Quick start

Add the dependency to your Cargo.toml:

[dependencies]
labkey-rs = "0.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

Then construct a client and query some data:

use labkey_rs::{ClientConfig, Credential, LabkeyClient};
use labkey_rs::query::SelectRowsOptions;
use labkey_rs::filter::{Filter, FilterType};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("LABKEY_API_KEY")?;

    let client = LabkeyClient::new(ClientConfig::new(
        "https://labkey.example.com/labkey",
        Credential::ApiKey(api_key),
        "/MyProject",
    ))?;

    let response = client.select_rows(
        SelectRowsOptions::builder()
            .schema_name("core")
            .query_name("Users")
            .filter_array(vec![
                Filter::new("Email", FilterType::Contains, "example.com"),
            ])
            .build(),
    ).await?;

    println!("Found {} users", response.row_count.unwrap_or(0));
    for row in &response.rows {
        println!("  {row:?}");
    }

    Ok(())
}

Authentication

The client supports four credential types:

use labkey_rs::Credential;

// API key from an environment variable (recommended)
let cred = Credential::ApiKey(
    std::env::var("LABKEY_API_KEY").expect("LABKEY_API_KEY must be set"),
);

// Basic auth (email + password — avoid hardcoding these)
let cred = Credential::Basic {
    email: "user@example.com".into(),
    password: "secret".into(),
};

// Read credentials from a ~/.netrc file
let cred = Credential::from_netrc("labkey.example.com")
    .expect("credentials found in .netrc");

// Guest (anonymous, no auth header)
let cred = Credential::Guest;

API keys are the standard LabKey authentication mechanism — just make sure the key comes from an environment variable, a secrets manager, or a credential file rather than being hardcoded in source. The from_netrc constructor reads ~/.netrc (or ~/_netrc on Windows), matching the Java client's NetrcCredentialsProvider, which is handy if you manage credentials for multiple servers. Guest access works only when the LabKey server permits anonymous reads.

Modules

Every endpoint is an async method on LabkeyClient. The methods are organized by the LabKey controller they target:

Module Description Endpoints
query Select, insert, update, delete rows; execute SQL; manage saved views 21
security Users, groups, containers, permissions, policies, impersonation 30
experiment Lineage queries, run groups, entity sequences, data objects 12
assay Assay designs, runs, batches, NAb study graphs, import 11
domain Domain designs, property usages, name expression validation 11
specimen Specimen repositories, request management, vial operations 11
visualization Saved visualizations and chart configurations 7
report Report creation, execution, and management 5
pipeline Pipeline status, file status, protocols 4
storage Freezer storage items (create, update, delete) 3
di Data integration transform runs and configuration 3
list List creation with shorthand fields 1
message Message board threads 1
participant_group Participant group sessions 1

Supporting types live in filter, sort, error, and common.

Filters and sorts

LabKey queries support a rich set of filter operators. Filters are built with the Filter type and the FilterType enum:

use labkey_rs::filter::{Filter, FilterType};

let filters = vec![
    Filter::new("Age", FilterType::GreaterThanOrEqual, "18"),
    Filter::new("Status", FilterType::In, "Active;Pending"),
    Filter::new("Name", FilterType::DoesNotStartWith, "Test"),
];

Sort specifications use the QuerySort type, which parses LabKey's comma-separated sort format:

use labkey_rs::sort::QuerySort;

// Parse LabKey's sort string format: column names, "-" prefix for descending
let sort = QuerySort::parse("Name,-Created");
assert_eq!(sort.to_string(), "Name,-Created");

Both filters and sorts are passed to query methods through their options builders.

Error handling

All client methods return Result<T, LabkeyError>. The error type covers network failures, structured API errors, deserialization problems, and unexpected responses:

use labkey_rs::{LabkeyClient, LabkeyError};
use labkey_rs::query::SelectRowsOptions;

async fn handle_query(client: &LabkeyClient) -> Result<(), LabkeyError> {
    let options = SelectRowsOptions::builder()
        .schema_name("core")
        .query_name("Users")
        .build();

    match client.select_rows(options).await {
        Ok(response) => println!("{} rows", response.row_count.unwrap_or(0)),
        Err(LabkeyError::Api { status, body }) => {
            eprintln!("Server error ({}): {:?}", status, body.exception);
        }
        Err(e) => eprintln!("Other error: {e}"),
    }
    Ok(())
}

LabKey sometimes returns HTTP 200 with an embedded exception in the JSON body instead of a proper error status code. The client detects this and returns LabkeyError::Api rather than a confusing deserialization error.

Security notes for SQL APIs

execute_sql and the feature-gated experimental SQL API accept raw SQL strings. Treat these as privileged interfaces.

  • Never concatenate untrusted input directly into SQL text.
  • Prefer allowlisted query templates over arbitrary user-supplied SQL.
  • Use least-privilege credentials for automation and sync jobs.
  • Apply result-size and rate limits in user-facing systems.

Automatic WAF encoding is for request compatibility with LabKey deployments behind web application firewalls; it is not a replacement for safe query construction.

Compatibility

This crate targets LabKey Server's API version 17.1, which is the response format used by all modern LabKey Server releases. The apiVersion=17.1 parameter is sent on every request. All response types are modeled against this format.

[!NOTE] labkey-rs is currently pre-1.0. Minor-version releases may include API adjustments while the library surface is still being refined.

The crate is pre-1.0 and the API may change. It has not yet been published to crates.io. The crate is pre-1.0 and the API may change.

Experimental APIs

Some APIs are intentionally feature-gated while they mature.

[!TIP] To enable experimental APIs, add the experimental feature and import the extension trait from query::experimental.

[dependencies]
labkey-rs = { version = "0.2", features = ["experimental"] }

Then import the extension trait where you call experimental methods:

use labkey_rs::query::experimental::{ExperimentalQueryExt, SqlExecuteOptions};

LabKey documentation

For background on the server-side concepts this client interacts with:

License

Licensed under either of Apache License, Version 2.0 or MIT License, at your option.

The upstream JavaScript client is licensed under Apache 2.0.