Snowflex.Transport.Http (Snowflex v1.2.1)

View Source

REST API transport implementation for Snowflake. See: https://docs.snowflake.com/en/developer-guide/sql-api/reference

Configuration Options

The HTTP transport supports the following configuration options:

Required Options

  • :account_name - Your Snowflake account identifier (e.g., "my-org-my-account")
  • :username - Your Snowflake username
  • :private_key_path - Path to your private key file (PEM format) OR
  • :private_key_from_string - Your private key as a string (PEM format)
  • :public_key_fingerprint - Fingerprint of your public key

Optional Options

  • :database - Default database to use
  • :schema - Default schema to use
  • :warehouse - Default warehouse to use
  • :role - Default role to use
  • :timeout - Query timeout in milliseconds (default: 45 seconds)
  • :token_lifetime - JWT token lifetime in milliseconds (default: 10 minutes)
  • :private_key_password - Password for the private key (if encrypted)
  • :async_poll_interval - Interval in milliseconds to poll for async execution status (default: 1000)
  • :max_retries - Maximum retry attempts for rate limits (default: 3)
  • :retry_base_delay - Base delay for exponential backoff in milliseconds (default: 1000)
  • :retry_max_delay - Maximum delay between retries in milliseconds (default: 8000)
  • :connect_options - Connection options for Finch pool configuration
  • :req_options - Additional options to pass to Req.new/1 (e.g., :plug for testing)

Account Name Handling

The transport automatically handles different Snowflake account name formats for JWT token generation:

  • For global accounts (e.g., "account-123.global.snowflakecomputing.com"):

    • Extracts the account identifier before the first hyphen
    • Example: "account-123" becomes "ACCOUNT"
  • For regional accounts (e.g., "account.us-east-1.snowflakecomputing.com"):

    • Extracts the account identifier before the first dot
    • Example: "account.us-east-1" becomes "ACCOUNT"

Authentication

The transport uses JWT authentication with RSA key pairs. The private key must be in PEM format and the public key fingerprint must be registered with Snowflake.

Private Key Configuration

Snowflex supports two ways to provide your private key for authentication:

1. File Path (traditional method)

config :my_app, MyApp.Repo,
  # ... other options ...
  private_key_path: "/path/to/your/private_key.pem"

2. String (inline method)

config :my_app, MyApp.Repo,
  # ... other options ...
  private_key_from_string: System.get_env("SNOWFLAKE_PRIVATE_KEY") || """
  -----BEGIN PRIVATE KEY-----
  MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC...
  -----END PRIVATE KEY-----
  """

Important notes:

  • You must provide either private_key_path OR private_key_from_string, not both
  • Both options accept PEM format private keys
  • The string method is useful when deploying to environments where file system access is restricted or when storing keys in environment variables/secrets management systems

Example Configuration

config :my_app, MyApp.Repo,
  adapter: Snowflex,
  transport: Snowflex.Transport.Http,
  account_name: "my-org-my-account",
  username: "my_user",
  private_key_path: "/path/to/key.pem",
  # OR alternatively use private_key_from_string instead of private_key_path:
  # private_key_from_string: "-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----",
  public_key_fingerprint: "abc123...",
  database: "MY_DB",
  schema: "MY_SCHEMA",
  warehouse: "MY_WH",
  role: "MY_ROLE",
  timeout: :timer.seconds(30),
  token_lifetime: :timer.minutes(15),
  # Retry configuration
  max_retries: 3,
  retry_base_delay: :timer.seconds(1),
  retry_max_delay: :timer.seconds(8)

Summary

Functions

Returns a specification to start this module under a supervisor.

Returns the current t:Req.Request for the transport.

Returns the current set of options for Req.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

client(pid)

@spec client(GenServer.server()) :: Req.Request.t()

Returns the current t:Req.Request for the transport.

Useful when you need to execute an arbitrary API request against Snowflake's REST API.

options(config)

@spec options(keyword()) :: {:ok, keyword()} | {:error, term()}

Returns the current set of options for Req.

This can be useful when you need to execute an arbitrary API request against Snowflake's REST API, but need more control over how the Req client is built.

To keep Snowflex's internal Req usage simpler, we do not support the full gamut of options that Req does, only the subset we rely upon. Your use case might necessitate changing/modifying/adding other options however.

For example, if you want to specify a different Finch pool to use, you currently can't, because Http sets the connection_options for Req. Req does not allow specifying connection_options AND finch at the same time.

We can use options/1 to get the current options, and then modify them as needed:

Example:

  {:ok, options} =
    :my_app
    |> Application.get_config(MyRepo)
    |> Snowflex.Transport.Http.options()

  options
  |> Keyword.delete(:connect_options)
  |> Keyword.put(:finch, MyFinch)
  |> Req.new()