Skip to content

SNOW-3155971: Snowflake restful implementation#638

Merged
sfc-gh-turbaszek merged 1 commit intomainfrom
NO-SNOW-SnowflakeRestful-further-implementation
Apr 7, 2026
Merged

SNOW-3155971: Snowflake restful implementation#638
sfc-gh-turbaszek merged 1 commit intomainfrom
NO-SNOW-SnowflakeRestful-further-implementation

Conversation

@sfc-gh-turbaszek
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings March 19, 2026 16:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the DatabaseDriver v1 surface to support a backward-compatible “REST” interface used by Snowflake CLI, by exposing master_token in connection info and adding new RPCs for “generic HTTP via core TLS client” and “token-request via master token”, with corresponding Python wrapper methods and integration tests.

Changes:

  • Add master_token to ConnectionGetInfoResponse and plumb it through Rust ↔ protobuf ↔ Python.
  • Add ConnectionSendHttp and ConnectionRequestToken RPCs and implement them in sf_core.
  • Implement SnowflakeRestful request/fetch/token-request methods in Python and add integration coverage; update pre-commit Python hook to run via uv.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
sf_core/src/protobuf/apis/database_driver_v1.rs Maps Rust connection info (now including master_token) into protobuf responses; adds RPC handlers that forward into the driver implementation.
sf_core/src/apis/database_driver_v1/connection.rs Adds core implementations for generic HTTP requests and token-request calls using the connection’s configured HTTP client/tokens.
protobuf/database_driver_v1.proto Extends the proto with master_token plus new HTTP/token-request messages and RPCs.
python/src/snowflake/connector/_internal/snowflake_restful.py Implements the Python-side REST compatibility wrapper by calling the new RPCs.
python/tests/integ/test_snowflake_restful.py Adds integration tests that mirror Snowflake CLI call patterns against connection.rest.
.pre-commit-config.yaml Switches Python pre-commit hook to run checks via uv.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py Outdated
@sfc-gh-turbaszek sfc-gh-turbaszek changed the title No snow snowflake restful further implementation SNOW-3155971: Snowflake restful implementation Mar 24, 2026
Copilot AI review requested due to automatic review settings March 24, 2026 09:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a backward-compatible “RESTful” interface for Snowflake CLI usage by extending the DatabaseDriverV1 RPC surface to (a) proxy generic HTTP calls through sf_core’s TLS-configured client and (b) support session token ISSUE/RENEW via the Snowflake /session/token-request endpoint, then wiring these capabilities into the Python connector’s connection.rest.

Changes:

  • Add Snowflake token-request support in sf_core and expose it via a new ConnectionRequestToken RPC.
  • Add a generic ConnectionSendHttp RPC to send HTTP requests using the connection’s configured HTTP/TLS client.
  • Expose server_url, master_token, and REST-style request/fetch helpers in Python, with new integration tests covering CLI-like call patterns.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
sf_core/src/rest/snowflake/mod.rs Adds token_request() and TokenRequestResult to call /session/token-request for ISSUE/RENEW.
sf_core/src/apis/database_driver_v1/connection.rs Adds connection_send_http_request() and connection_token_request() driver APIs; includes returning master_token in connection info.
sf_core/src/apis/database_driver_v1/error.rs Introduces ApiError::HttpRequest to preserve reqwest::Error context.
sf_core/src/protobuf/apis/database_driver_v1.rs Wires new RPC methods and maps master_token into ConnectionGetInfoResponse.
protobuf/database_driver_v1.proto Extends the proto API: master_token, ConnectionSendHttp, and ConnectionRequestToken.
python/src/snowflake/connector/_internal/snowflake_restful.py Implements server_url, master_token, request(), fetch(), and _token_request() using the new RPCs.
python/tests/integ/test_snowflake_restful.py Adds integration tests validating REST-compat properties and request/token flows.
.pre-commit-config.yaml Updates Python pre-commit hook invocation to run via uv.

Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread sf_core/src/rest/snowflake/mod.rs
Comment thread sf_core/src/rest/snowflake/mod.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread sf_core/src/protobuf/apis/database_driver_v1.rs Outdated
Comment thread protobuf/database_driver_v1.proto Outdated
Comment thread protobuf/database_driver_v1.proto
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py Outdated
@sfc-gh-turbaszek sfc-gh-turbaszek marked this pull request as ready for review March 25, 2026 09:17
@sfc-gh-turbaszek sfc-gh-turbaszek requested a review from a team as a code owner March 25, 2026 09:17
Copilot AI review requested due to automatic review settings March 25, 2026 09:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Comment thread sf_core/src/rest/snowflake/mod.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread sf_core/src/rest/snowflake/mod.rs Outdated
Comment thread protobuf/database_driver_v1.proto Outdated
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py Outdated
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Copilot AI review requested due to automatic review settings March 25, 2026 16:41
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from 136311d to 5cc991d Compare March 25, 2026 16:41
Comment thread protobuf/database_driver_v1.proto Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Comment thread sf_core/src/protobuf/apis/database_driver_v1.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs Outdated
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread sf_core/src/rest/snowflake/mod.rs
Comment thread sf_core/src/rest/snowflake/mod.rs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Comment thread sf_core/src/protobuf/apis/database_driver_v1.rs Outdated
Comment thread sf_core/src/protobuf/apis/database_driver_v1.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from 8610bf4 to d404957 Compare March 27, 2026 09:51
Copilot AI review requested due to automatic review settings March 27, 2026 11:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread sf_core/src/rest/snowflake/mod.rs Outdated
Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread sf_core/src/apis/database_driver_v1/connection.rs
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py Outdated
Copilot AI review requested due to automatic review settings March 30, 2026 13:15
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from 22706d2 to dec5bc4 Compare March 30, 2026 13:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

@property
def _port(self) -> int | None:
return urlparse(self._connection_info.server_url).port or 443
url = self._connection_info.server_url
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_port is derived only from parsing connection_info.server_url, and falls back to 443 when server_url is unset. Since ConnectionGetInfoResponse also has a dedicated port field, consider preferring that field (when present) so _port stays accurate even if server_url is temporarily unavailable.

Suggested change
url = self._connection_info.server_url
info = self._connection_info
# Prefer explicit port from connection info when available
if getattr(info, "port", None):
return info.port
# Fall back to deriving port from server_url, defaulting to 443
url = info.server_url

Copilot uses AI. Check for mistakes.
Comment on lines +95 to +101
#[snafu(display("HTTP request failed: {context}"))]
HttpRequest {
context: String,
#[snafu(implicit)]
location: Location,
source: reqwest::Error,
},
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ApiError::HttpRequest's display string only includes the high-level {context} and omits the underlying reqwest::Error. This can make the top-level error message much less actionable (e.g., missing "connection refused" / "timeout" details) unless callers explicitly inspect the root cause chain. Consider including {source} in the display format so the primary error message carries the concrete failure reason.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ valid comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — changed display to "HTTP request failed: {context}: {source}" so the underlying reqwest error (timeout, connection refused, etc.) is included.

host = self._host
if not host:
raise ValueError("server_url and host are both unavailable from connection info")
return f"https://{host}:443"
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server_url fallback hard-codes https://{host}:443 when connection_info.server_url is unset, ignoring the connection's configured port/protocol (ConnectionGetInfoResponse.port / _protocol). This can produce an incorrect URL for non-443 ports or non-https setups. Consider composing the fallback from the available host + port fields (and protocol if available), rather than hard-coding 443/https.

Suggested change
return f"https://{host}:443"
protocol = self._protocol or "https"
port = self._port or 443
return f"{protocol}://{host}:{port}"

Copilot uses AI. Check for mistakes.
Comment thread sf_core/src/rest/snowflake/mod.rs Outdated
Comment on lines +781 to +787
let refresh_response =
response
.json::<TokenRequestResponse>()
.await
.context(CommunicationSnafu {
context: "Failed to parse token request response",
})?;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In token_request, the local variable is named refresh_response, but this function is parsing the token request response. Renaming it (e.g., token_response) would avoid confusion with refresh_session and make the control flow easier to follow.

Copilot uses AI. Check for mistakes.
parsed = urlparse(connection.rest.server_url)
assert parsed.scheme in ("http", "https")
assert parsed.hostname is not None
assert len(parsed.hostname) > 0
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_server_url_contains_host_and_port claims server_url should be protocol://host:port, but the assertions only check scheme and hostname (no assertion for parsed.port). Either assert parsed.port is not None / equals the expected value, or adjust the test name/docstring to match the actual contract being verified.

Suggested change
assert len(parsed.hostname) > 0
assert len(parsed.hostname) > 0
assert parsed.port is not None

Copilot uses AI. Check for mistakes.
return urlparse(self._connection_info.server_url).scheme
url = self._connection_info.server_url
if not url:
return "https"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like "https" could be constant, something like DEFAULT_PROTOCOL

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for port?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — extracted DEFAULT_PROTOCOL = "https" and DEFAULT_PORT = 443 as module-level constants.

Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
raise ValueError(f"Unsupported HTTP method '{method}'. Only 'get' and 'post' are supported.")

headers = {
"Content-Type": "application/json",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for "application/json" we could utilize some constants

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — extracted as APPLICATION_JSON constant.

self,
url: str,
body: dict | None = None,
method: str = "post",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that these would be cleaner as enums, but I guess it must stay for backward compatibility, still could be extracted to some constants at least

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced a TokenRequestType proto enum with ISSUE and RENEW values. The Python side still accepts strings for backward compatibility but maps them to the proto enum via _TOKEN_REQUEST_TYPE_MAP.

Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in snowflake_restful.py we claim

class SnowflakeRestful:
    """Internal only iterface to underlying v1 API"""

but here we're testing with v2 API, it looks like it needs clarification

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the class docstring to clarify that SnowflakeRestful wraps the driver's internal gRPC API but is used by CLI to issue Snowflake REST API calls (both v1 and v2).

Comment thread protobuf/database_driver_v1.proto
Comment thread python/tests/integ/test_snowflake_restful.py
Copilot AI review requested due to automatic review settings March 31, 2026 12:42
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from cdc0d73 to de27564 Compare March 31, 2026 12:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py Outdated
Copilot AI review requested due to automatic review settings March 31, 2026 14:49
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread sf_core/src/apis/database_driver_v1/connection.rs
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from b3918b7 to 86bcc2f Compare April 7, 2026 11:22
Comment thread python/src/snowflake/connector/_internal/snowflake_restful.py
Comment thread python/tests/integ/test_snowflake_restful.py Outdated
Comment thread sf_core/src/rest/snowflake/mod.rs
Copy link
Copy Markdown
Contributor

@sfc-gh-asolarski sfc-gh-asolarski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BD number requires change in tests, besides that only nitpicks

Expose master_token via ConnectionGetInfoResponse and implement the three
REST methods (request, fetch, _token_request) that Snowflake CLI depends
on. Uses the requests library for HTTP calls with session/master token
authentication. Adds integration tests covering all properties and
request patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 7, 2026 13:11
@sfc-gh-turbaszek sfc-gh-turbaszek force-pushed the NO-SNOW-SnowflakeRestful-further-implementation branch from 86bcc2f to 70809ee Compare April 7, 2026 13:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment on lines +731 to +747
pub async fn token_request(
client: &reqwest::Client,
server_url: &str,
client_info: &ClientInfo,
tokens: &SessionTokens,
request_type: &str,
) -> Result<TokenRequestResult, RestError> {
let token_url = Url::parse(server_url)
.and_then(|base| base.join(TOKEN_REQUEST_PATH))
.context(UrlJoinSnafu {
path: TOKEN_REQUEST_PATH,
})?;

let body = serde_json::json!({
"oldSessionToken": tokens.session_token.reveal(),
"requestType": request_type,
});
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

token_request() takes request_type: &str and forwards it directly into the request body and error variants. Since this is a public API, callers can pass arbitrary values and only discover the mistake via a server-side failure (potentially with a confusing error message). Consider validating request_type up-front (e.g., only allow "ISSUE"/"RENEW") or changing the parameter type to a dedicated enum to make invalid request types unrepresentable.

Copilot uses AI. Check for mistakes.
.build()
.unwrap(),
);
conn.server_url = Some("https://192.0.2.1:9".into());
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new HTTP tests use server_url = "https://192.0.2.1:9" and rely on a network-layer failure to proceed. Even with a 100ms client timeout, connecting to a TEST-NET address can be slower/flaky depending on CI networking (timeouts vs immediate refusal), which can make these unit tests intermittently slow or fail. Consider using a deterministic local unreachable target (e.g., https://127.0.0.1:9 where connection refusal is immediate) or a lightweight mock HTTP server to avoid dependence on external routing behavior.

Suggested change
conn.server_url = Some("https://192.0.2.1:9".into());
conn.server_url = Some("https://127.0.0.1:9".into());

Copilot uses AI. Check for mistakes.
@sfc-gh-turbaszek sfc-gh-turbaszek added this pull request to the merge queue Apr 7, 2026
Merged via the queue into main with commit bb8c337 Apr 7, 2026
75 of 76 checks passed
@sfc-gh-turbaszek sfc-gh-turbaszek deleted the NO-SNOW-SnowflakeRestful-further-implementation branch April 7, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants