Skip to content

Commit 43e3535

Browse files
authored
Convert context into query string for FGA queries (#438)
* Convert context into query string for FGA queries * Linter * Include full url with query params from mock helper * Update query test to check full request url
1 parent 3e9d91e commit 43e3535

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

tests/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
cast,
1212
)
1313
from unittest.mock import AsyncMock, MagicMock
14+
import urllib.parse
1415

1516
import httpx
1617
import pytest
@@ -162,6 +163,14 @@ def inner(
162163
def capture_and_mock(*args, **kwargs):
163164
request_kwargs.update(kwargs)
164165

166+
# Capture full URL with encoded params while keeping original URL
167+
if kwargs and "params" in kwargs and kwargs["params"]:
168+
# Convert params to query string with proper URL encoding
169+
query_string = urllib.parse.urlencode(
170+
kwargs["params"], doseq=True, quote_via=urllib.parse.quote_plus
171+
)
172+
request_kwargs.update({"full_url": f"{kwargs['url']}?{query_string}"})
173+
165174
return httpx.Response(
166175
status_code=status_code,
167176
headers=headers,

tests/test_fga.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,22 @@ def test_query(self, mock_query_response, mock_http_client_with_response):
534534
warrant_token="warrant_token",
535535
)
536536
assert response.dict(exclude_none=True) == mock_query_response
537+
538+
def test_query_with_context(
539+
self, mock_query_response, capture_and_mock_http_client_request
540+
):
541+
request_kwargs = capture_and_mock_http_client_request(
542+
self.http_client, mock_query_response, 200
543+
)
544+
545+
response = self.fga.query(
546+
q="select member of type user for permission:view-docs",
547+
order="asc",
548+
warrant_token="warrant_token",
549+
context={"region": "us", "subscription": "pro"},
550+
)
551+
552+
assert request_kwargs["url"] == "https://api.workos.test/fga/v1/query"
553+
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"
554+
assert request_kwargs["full_url"] == expected_full_url
555+
assert response.dict(exclude_none=True) == mock_query_response

workos/fga.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
from typing import Any, Mapping, Optional, Protocol, Sequence
23
from workos.types.fga import (
34
CheckOperation,
@@ -621,11 +622,16 @@ def query(
621622
"after": after,
622623
"context": context,
623624
}
625+
parsed_list_params = {
626+
key: json.dumps(value) if key == "context" and value is not None else value
627+
for key, value in list_params.items()
628+
if value is not None
629+
}
624630

625631
response = self._http_client.request(
626632
"fga/v1/query",
627633
method=REQUEST_METHOD_GET,
628-
params=list_params,
634+
params=parsed_list_params,
629635
headers={"Warrant-Token": warrant_token} if warrant_token else None,
630636
)
631637

0 commit comments

Comments
 (0)