Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.

Commit 6915a8e

Browse files
authored
Merge pull request #8 from apilytics/query-params
Send query parameters in addition to path in middlewares
2 parents 8358eca + 51fd816 commit 6915a8e

File tree

8 files changed

+66
-3
lines changed

8 files changed

+66
-3
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Send query parameters in addition to the path.
13+
1014
## [1.0.2] - 2022-01-16
1115

1216
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ def my_apilytics_middleware(request, get_response):
7676
with ApilyticsSender(
7777
api_key=api_key,
7878
path=request.path,
79+
query=request.query_string,
7980
method=request.method,
8081
) as sender:
8182
response = get_response(request)

apilytics/core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ApilyticsSender:
2727
with ApilyticsSender(
2828
api_key="<your-api-key>",
2929
path=request.path,
30+
query=request.query_string,
3031
method=request.method,
3132
) as sender:
3233
response = get_response(request)
@@ -45,6 +46,7 @@ def __init__(
4546
api_key: str,
4647
path: str,
4748
method: str,
49+
query: Optional[str] = None,
4850
apilytics_integration: Optional[str] = None,
4951
integrated_library: Optional[str] = None,
5052
) -> None:
@@ -54,6 +56,8 @@ def __init__(
5456
Args:
5557
api_key: The API key for your Apilytics origin.
5658
path: Path of the user's HTTP request, e.g. "/foo/bar/123".
59+
query: Optional query string of the user's HTTP request e.g. "key=val&other=123".
60+
An empty string and None are treated equally. Can have an optional "?" at the start.
5761
method: Method of the user's HTTP request, e.g. "GET".
5862
apilytics_integration: Name of the Apilytics integration that's calling this,
5963
e.g. "apilytics-python-django". No need to pass this when calling from user code.
@@ -63,6 +67,7 @@ def __init__(
6367
self._api_key = api_key
6468
self._path = path
6569
self._method = method
70+
self._query = query
6671
self._status_code: Optional[int] = None
6772

6873
self._apilytics_version = self._apilytics_version_template.format(
@@ -115,6 +120,7 @@ def _send_metrics(self) -> None:
115120
)
116121
data = {
117122
"path": self._path,
123+
**({"query": self._query} if self._query else {}),
118124
"method": self._method,
119125
"statusCode": self._status_code,
120126
"timeMillis": (self._end_time_ns - self._start_time_ns) // 1_000_000,

apilytics/django.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ def __call__(self, request: django.http.HttpRequest) -> django.http.HttpResponse
4242
with apilytics.core.ApilyticsSender(
4343
api_key=self.api_key,
4444
path=request.path,
45-
method=request.method or "",
45+
query=request.META.get("QUERY_STRING"),
46+
method=request.method or "", # Typed as Optional, should never be None.
4647
apilytics_integration="apilytics-python-django",
4748
integrated_library=f"django/{django.__version__}",
4849
) as sender:

apilytics/fastapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ async def dispatch(
5151
with apilytics.core.ApilyticsSender(
5252
api_key=self.api_key,
5353
path=request.url.path,
54+
query=request.url.query,
5455
method=request.method,
5556
apilytics_integration="apilytics-python-fastapi",
5657
integrated_library=f"fastapi/{fastapi.__version__}",

tests/django/test_django.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_middleware_should_call_apilytics_api(
4343
assert isinstance(data["timeMillis"], int)
4444

4545

46-
def test_middleware_should_not_send_query_params(
46+
def test_middleware_should_send_query_params(
4747
mocked_urlopen: unittest.mock.MagicMock,
4848
) -> None:
4949
client.handler.load_middleware()
@@ -55,6 +55,7 @@ def test_middleware_should_not_send_query_params(
5555
data = tests.conftest.decode_request_data(call_kwargs["data"])
5656
assert data["method"] == "POST"
5757
assert data["path"] == "/dummy/123/path/"
58+
assert data["query"] == "param=foo&param2=bar"
5859
assert data["statusCode"] == 201
5960
assert isinstance(data["timeMillis"], int)
6061

tests/fastapi/test_fastapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def test_middleware_should_call_apilytics_api(
4343
assert isinstance(data["timeMillis"], int)
4444

4545

46-
def test_middleware_should_not_send_query_params(
46+
def test_middleware_should_send_query_params(
4747
mocked_urlopen: unittest.mock.MagicMock,
4848
) -> None:
4949
response = client.post("/dummy/123/path/?param=foo&param2=bar")
@@ -54,6 +54,7 @@ def test_middleware_should_not_send_query_params(
5454
data = tests.conftest.decode_request_data(call_kwargs["data"])
5555
assert data["method"] == "POST"
5656
assert data["path"] == "/dummy/123/path/"
57+
assert data["query"] == "param=foo&param2=bar"
5758
assert data["statusCode"] == 201
5859
assert isinstance(data["timeMillis"], int)
5960

tests/test_core.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,54 @@ def test_apilytics_sender_should_call_apilytics_api(
4141
assert isinstance(data["timeMillis"], int)
4242

4343

44+
def test_middleware_should_send_query_params(
45+
mocked_urlopen: unittest.mock.MagicMock,
46+
) -> None:
47+
with apilytics.core.ApilyticsSender(
48+
api_key="dummy-key",
49+
path="/path",
50+
query="key=value?other=123",
51+
method="PUT",
52+
) as sender:
53+
sender.set_response_info(status_code=200)
54+
55+
assert mocked_urlopen.call_count == 1
56+
__, call_kwargs = mocked_urlopen.call_args
57+
data = tests.conftest.decode_request_data(call_kwargs["data"])
58+
assert data["path"] == "/path"
59+
assert data["query"] == "key=value?other=123"
60+
61+
62+
def test_middleware_should_not_send_empty_query_params(
63+
mocked_urlopen: unittest.mock.MagicMock,
64+
) -> None:
65+
with apilytics.core.ApilyticsSender(
66+
api_key="dummy-key",
67+
path="/",
68+
query="",
69+
method="GET",
70+
) as sender:
71+
sender.set_response_info(status_code=200)
72+
73+
assert mocked_urlopen.call_count == 1
74+
__, call_kwargs = mocked_urlopen.call_args
75+
data = tests.conftest.decode_request_data(call_kwargs["data"])
76+
assert "query" not in data
77+
78+
with apilytics.core.ApilyticsSender(
79+
api_key="dummy-key",
80+
path="/",
81+
query=None,
82+
method="GET",
83+
) as sender:
84+
sender.set_response_info(status_code=200)
85+
86+
assert mocked_urlopen.call_count == 2
87+
__, call_kwargs = mocked_urlopen.call_args
88+
data = tests.conftest.decode_request_data(call_kwargs["data"])
89+
assert "query" not in data
90+
91+
4492
@unittest.mock.patch(
4593
"apilytics.core.urllib.request.urlopen",
4694
side_effect=urllib.error.URLError("testing"),

0 commit comments

Comments
 (0)