Skip to content

estie-inc/snowflake-connector-rs

Repository files navigation

Snowflake Connector for Rust

test Crates.io

A Rust client for Snowflake, which enables you to connect to Snowflake and run queries.

MSRV

The minimum supported Rust version (MSRV) is 1.88.

Usage

#[derive(Debug, PartialEq, snowflake_connector_rs::FromRow)]
struct ExampleRow {
    id: i64,
    value: String,
}

let session_config = SnowflakeSessionConfig::default()
    .with_role("ROLE")
    .with_warehouse("WAREHOUSE")
    .with_database("DATABASE")
    .with_schema("SCHEMA");

let query_config = SnowflakeQueryConfig::default()
    .with_async_query_completion_timeout(std::time::Duration::from_secs(30));

let client = SnowflakeClient::new(
    SnowflakeClientConfig::new(
        "USERNAME",
        "ACCOUNT",
        SnowflakeAuthConfig::password("PASSWORD"),
    )
    .with_session(session_config)
    .with_query(query_config),
)?;
let session = client.create_session().await?;

session
    .query("CREATE TEMPORARY TABLE example (id NUMBER, value STRING)")
    .await?;
session
    .query("INSERT INTO example (id, value) VALUES (1, 'hello'), (2, 'world')")
    .await?;

let dynamic_rows = session
    .query("SELECT id, value FROM example ORDER BY id")
    .await?
    .collect()
    .await?;
assert_eq!(dynamic_rows.len(), 2);

let rows: Vec<ExampleRow> = session
    .query_as::<ExampleRow, _>("SELECT id, value FROM example ORDER BY id")
    .await?
    .collect()
    .await?;
assert_eq!(
    rows,
    vec![
        ExampleRow {
            id: 1,
            value: "hello".to_string(),
        },
        ExampleRow {
            id: 2,
            value: "world".to_string(),
        },
    ]
);

let typed_table = session
    .query_as::<ExampleRow, _>("SELECT id, value FROM example ORDER BY id")
    .await?
    .collect_table()
    .await?;
assert_eq!(typed_table.row_count(), 2);

let mut result = session
    .query_as::<ExampleRow, _>("SELECT id, value FROM example ORDER BY id")
    .await?;
while let Some(table) = result.next_table().await? {
    for row in table.rows() {
        let row = row?;
        println!("{row:?}");
    }
}

let result = session.query("SELECT id, value FROM example ORDER BY id").await?;
let table = result.collect_table().await?;
assert_eq!(table.row_count(), 2);

Custom Endpoint

To override the default Snowflake endpoint (e.g. for testing or non-default network setups):

use url::Url;
let auth = SnowflakeAuthConfig::password("PASSWORD");
let endpoint = SnowflakeEndpointConfig::custom_base_url(
    Url::parse("https://custom-host.example.com").unwrap(),
);
let client = SnowflakeClient::new(
    SnowflakeClientConfig::new("USERNAME", "ACCOUNT", auth)
        .with_endpoint(endpoint),
)?;

Proxy

To route requests through an HTTP proxy:

use url::Url;
let auth = SnowflakeAuthConfig::password("PASSWORD");
let proxy = SnowflakeProxyConfig::new(
    Url::parse("http://proxy.example.com:8080").unwrap(),
)
.with_basic_auth("proxy_user", "proxy_pass");

let transport = SnowflakeTransportConfig::default().with_proxy(proxy);
let client = SnowflakeClient::new(
    SnowflakeClientConfig::new("USERNAME", "ACCOUNT", auth)
        .with_transport(transport),
)?;

Features

This crate supports optional features to decrypt legacy keys that use DES or 3DES encryption. These algorithms are considered insecure and should only be used for legacy compatibility.

  • pkcs8-des: Enables DES decryption support
  • pkcs8-3des: Enables 3DES decryption support
  • derive: Re-exports the FromRow derive macro (enabled by default)
  • key-pair-auth: Enables key-pair authentication support (enabled by default)
  • external-browser-sso: Enables external browser SSO authentication support

Note

The external-browser-sso feature is experimental. The implementation and API may change in future releases, and stability or backward compatibility is not guaranteed. Use this feature with caution in production environments. Please open an issue for bugs or feature requests.

External Browser SSO Use Cases

Typical configurations for the external-browser-sso feature:

  • Local default (auto browser launch, localhost callback, auto-picked port)
    use snowflake_connector_rs::{ExternalBrowserConfig, SnowflakeAuthConfig};
    let auth = SnowflakeAuthConfig::external_browser(ExternalBrowserConfig::default());
  • Docker/container setup (manual open with explicit callback bind address/port)
     use std::net::Ipv4Addr;
     use snowflake_connector_rs::{BrowserLaunchMode, ExternalBrowserConfig, SnowflakeAuthConfig};
     let external_browser = ExternalBrowserConfig::with_callback_listener(
         BrowserLaunchMode::Manual,
         Ipv4Addr::UNSPECIFIED.into(),
         3037,
     );
     let auth = SnowflakeAuthConfig::external_browser(external_browser);
  • Without callback listener mode (manual redirected URL input)
     use std::num::NonZeroU16;
     use snowflake_connector_rs::{BrowserLaunchMode, ExternalBrowserConfig, SnowflakeAuthConfig};
     let redirect_port = NonZeroU16::new(3037).unwrap();
     let external_browser =
         ExternalBrowserConfig::without_callback_listener(BrowserLaunchMode::Manual, redirect_port);
     let auth = SnowflakeAuthConfig::external_browser(external_browser);

For Docker/container setup, make sure that:

  • your Snowflake OAuth redirect URI allows the same callback port (for example 3037), and
  • the callback port is mapped to the host (for example -p 3037:3037 or equivalent in Compose).

0.0.0.0 binds on all interfaces in the container. Use the minimum required network exposure for your environment.

In WithoutCallbackListener mode:

  • no local server is started, so localhost:<redirect_port> is not actually listened on by this connector.
  • a non-zero redirect_port is still required because Snowflake uses BROWSER_MODE_REDIRECT_PORT to construct the browser redirect URL.
  • the browser may show a connection error page at localhost:<redirect_port> after login; copy that redirected URL and paste it into the terminal prompt so the connector can extract the token.

About

Snowflake Connector for Rust

Resources

License

Stars

Watchers

Forks

Contributors