diff --git a/tests/conftest.py b/tests/conftest.py index c89fc788..76d422b7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,6 +11,7 @@ cast, ) from unittest.mock import AsyncMock, MagicMock +import urllib.parse import httpx import pytest @@ -162,6 +163,14 @@ def inner( def capture_and_mock(*args, **kwargs): request_kwargs.update(kwargs) + # Capture full URL with encoded params while keeping original URL + if kwargs and "params" in kwargs and kwargs["params"]: + # Convert params to query string with proper URL encoding + query_string = urllib.parse.urlencode( + kwargs["params"], doseq=True, quote_via=urllib.parse.quote_plus + ) + request_kwargs.update({"full_url": f"{kwargs['url']}?{query_string}"}) + return httpx.Response( status_code=status_code, headers=headers, diff --git a/tests/test_fga.py b/tests/test_fga.py index 6a2d5d35..5bf3e046 100644 --- a/tests/test_fga.py +++ b/tests/test_fga.py @@ -534,3 +534,22 @@ def test_query(self, mock_query_response, mock_http_client_with_response): warrant_token="warrant_token", ) assert response.dict(exclude_none=True) == mock_query_response + + def test_query_with_context( + self, mock_query_response, capture_and_mock_http_client_request + ): + request_kwargs = capture_and_mock_http_client_request( + self.http_client, mock_query_response, 200 + ) + + response = self.fga.query( + q="select member of type user for permission:view-docs", + order="asc", + warrant_token="warrant_token", + context={"region": "us", "subscription": "pro"}, + ) + + assert request_kwargs["url"] == "https://api.workos.test/fga/v1/query" + expected_full_url = "https://api.workos.test/fga/v1/query?q=select+member+of+type+user+for+permission%3Aview-docs&limit=10&order=asc&context=%7B%22region%22%3A+%22us%22%2C+%22subscription%22%3A+%22pro%22%7D" + assert request_kwargs["full_url"] == expected_full_url + assert response.dict(exclude_none=True) == mock_query_response diff --git a/workos/fga.py b/workos/fga.py index ae52b9b0..5b143b28 100644 --- a/workos/fga.py +++ b/workos/fga.py @@ -1,3 +1,4 @@ +import json from typing import Any, Mapping, Optional, Protocol, Sequence from workos.types.fga import ( CheckOperation, @@ -621,11 +622,16 @@ def query( "after": after, "context": context, } + parsed_list_params = { + key: json.dumps(value) if key == "context" and value is not None else value + for key, value in list_params.items() + if value is not None + } response = self._http_client.request( "fga/v1/query", method=REQUEST_METHOD_GET, - params=list_params, + params=parsed_list_params, headers={"Warrant-Token": warrant_token} if warrant_token else None, )