Conversation
…ers, byDate endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis pull request introduces a new StatsApi feature to the Mailtrap client library. It adds a Stats API resource with five public endpoints (get, byDomains, byCategories, byEmailServiceProviders, byDate) for querying and grouping sending statistics, along with corresponding TypeScript types, a comprehensive test suite, example usage, and updates the package version to 4.5.0. Changes
Sequence DiagramsequenceDiagram
participant Client as User Code
participant MailtrapClient as MailtrapClient
participant StatsApi as StatsApi
participant Axios as Axios
participant Backend as Backend API
Client->>MailtrapClient: client.stats.get(params)
MailtrapClient->>StatsApi: initialize (lazy singleton)
MailtrapClient->>StatsApi: get(params)
StatsApi->>StatsApi: buildQueryParams(params)
StatsApi->>Axios: GET /stats?start_date=...&filters[]
Axios->>Backend: HTTP GET request
Backend-->>Axios: JSON response
Axios->>Axios: transform to response.data
StatsApi-->>Client: SendingStats object
alt Grouped Stats (byDomains, byCategories, etc.)
Client->>MailtrapClient: client.stats.byDomains(params)
MailtrapClient->>StatsApi: byDomains(params)
StatsApi->>StatsApi: groupedStats('domains', params)
StatsApi->>Axios: GET /stats/grouping/domains?...
Axios->>Backend: HTTP GET request
Backend-->>Axios: JSON array response
StatsApi->>StatsApi: map to SendingStatGroup[]
StatsApi-->>Client: SendingStatGroup[] array
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CHANGELOG.md`:
- Around line 1-2: Update the release header "## [4.5.0] - 2025-03-06" in
CHANGELOG.md to the correct 2026 release date (replace "2025-03-06" with the
actual 2026 date for the 4.5.0 release) so the chronology with "## [4.4.0] -
2025-12-08" is correct.
In `@src/lib/api/resources/Stats.ts`:
- Around line 100-121: The buildQueryParams method is manually appending "[]" to
array parameter keys (e.g., "sending_domain_ids[]") which causes
double-bracketed query strings when Axios serializes arrays; update
Stats.buildQueryParams (accepting StatsFilterParams) to use plain keys
("sending_domain_ids", "sending_streams", "categories",
"email_service_providers") without the "[]" suffix so axios.get(..., { params:
buildQueryParams(...) }) will serialize arrays correctly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d342a8a2-ed69-490b-9da4-f213fcbf0fa8
📒 Files selected for processing (8)
CHANGELOG.mdexamples/general/stats.tspackage.jsonsrc/__tests__/lib/api/resources/Stats.test.tssrc/index.tssrc/lib/api/General.tssrc/lib/api/resources/Stats.tssrc/types/api/stats.ts
| ## [4.5.0] - 2025-03-06 | ||
| - Add StatsApi with get, byDomains, byCategories, byEmailServiceProviders, byDate endpoints |
There was a problem hiding this comment.
Fix the 4.5.0 release date.
4.5.0 is listed as 2025-03-06, but the next entry below is 4.4.0 on 2025-12-08. That chronology can't be correct, so this should be updated to the actual 2026 release date before publishing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@CHANGELOG.md` around lines 1 - 2, Update the release header "## [4.5.0] -
2025-03-06" in CHANGELOG.md to the correct 2026 release date (replace
"2025-03-06" with the actual 2026 date for the 4.5.0 release) so the chronology
with "## [4.4.0] - 2025-12-08" is correct.
| private static buildQueryParams( | ||
| params: StatsFilterParams | ||
| ): Record<string, unknown> { | ||
| const query: Record<string, unknown> = { | ||
| start_date: params.start_date, | ||
| end_date: params.end_date, | ||
| }; | ||
|
|
||
| if (params.sending_domain_ids) { | ||
| query["sending_domain_ids[]"] = params.sending_domain_ids; | ||
| } | ||
| if (params.sending_streams) { | ||
| query["sending_streams[]"] = params.sending_streams; | ||
| } | ||
| if (params.categories) { | ||
| query["categories[]"] = params.categories; | ||
| } | ||
| if (params.email_service_providers) { | ||
| query["email_service_providers[]"] = params.email_service_providers; | ||
| } | ||
|
|
||
| return query; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
import io
import json
import tarfile
import urllib.request
def inspect(version: str) -> None:
meta = json.load(urllib.request.urlopen(f"https://registry.npmjs.org/axios/{version}"))
tarball_url = meta["dist"]["tarball"]
tarball_bytes = urllib.request.urlopen(tarball_url).read()
with tarfile.open(fileobj=io.BytesIO(tarball_bytes), mode="r:gz") as tar:
member = next(m for m in tar.getmembers() if m.name.endswith("lib/helpers/buildURL.js"))
source = tar.extractfile(member).read().decode()
print(f"\n--- axios {version} ---")
for line_no, line in enumerate(source.splitlines(), 1):
if "key = key + '[]'" in line or 'key = key + "[]"' in line:
print(f"{line_no}: {line.strip()}")
for version in ("0.27.2", "1.12.0"):
inspect(version)
PYRepository: mailtrap/mailtrap-nodejs
Length of output: 2687
🏁 Script executed:
# Check if the Stats.ts file exists and inspect the implementation
git ls-files | grep -i statsRepository: mailtrap/mailtrap-nodejs
Length of output: 193
🌐 Web query:
Axios array parameter serialization behavior how does axios handle array values in params
💡 Result:
Axios serializes params into the URL query string. For array values, the default behavior (Axios v1.x) is “empty brackets” format—i.e., it repeats the key and appends []:
axios.get("/search", { params: { tags: ["a", "b"] } });
// -> /search?tags[]=a&tags[]=bAxios exposes this via paramsSerializer.indexes, where the documented options are: null = no brackets, false (default) = empty brackets, true = indexed brackets. [1]
Examples:
// tags=a&tags=b
axios.get("/search", {
params: { tags: ["a", "b"] },
paramsSerializer: { indexes: null }
});
// tags[]=a&tags[]=b (default)
axios.get("/search", {
params: { tags: ["a", "b"] },
paramsSerializer: { indexes: false }
});
// tags[0]=a&tags[1]=b
axios.get("/search", {
params: { tags: ["a", "b"] },
paramsSerializer: { indexes: true }
});If you need other formats (e.g., comma-separated), you must provide a custom paramsSerializer.serialize (often implemented with qs.stringify(...)). [1][2]
Sources:
[1] Axios GitHub README – paramsSerializer and indexes options https://github.com/axios/axios
[2] Stack Overflow – using custom paramsSerializer / qs for alternate array formats https://stackoverflow.com/questions/74025557/correct-way-of-using-axios-paramsserializer-in-its-version-1-x
🏁 Script executed:
# Read the Stats.ts file to confirm the implementation
sed -n '90,125p' src/lib/api/resources/Stats.ts | cat -nRepository: mailtrap/mailtrap-nodejs
Length of output: 1167
🏁 Script executed:
# Check how axios is being used in this file
rg -A 3 "axios\.(get|post|request)" src/lib/api/resources/Stats.tsRepository: mailtrap/mailtrap-nodejs
Length of output: 50
🏁 Script executed:
# Look at the test file to see what's being tested
cat -n src/__tests__/lib/api/resources/Stats.test.ts | head -100Repository: mailtrap/mailtrap-nodejs
Length of output: 3267
🏁 Script executed:
# Get more context around the axios call in Stats.ts
sed -n '85,105p' src/lib/api/resources/Stats.ts | cat -nRepository: mailtrap/mailtrap-nodejs
Length of output: 744
🏁 Script executed:
# Search for the axios.get call in Stats.ts
rg -B 5 -A 5 "axios\.get|\.get\(" src/lib/api/resources/Stats.ts | head -30Repository: mailtrap/mailtrap-nodejs
Length of output: 50
🏁 Script executed:
# Check the test assertions - look for specific test cases with array filters
rg -A 20 "sending_domain_ids|byDomains" src/__tests__/lib/api/resources/Stats.test.tsRepository: mailtrap/mailtrap-nodejs
Length of output: 2482
🏁 Script executed:
# Check the Stats.ts class definition and client property
head -50 src/lib/api/resources/Stats.ts | cat -nRepository: mailtrap/mailtrap-nodejs
Length of output: 1558
🏁 Script executed:
# Also check if there's a custom paramsSerializer being used anywhere
rg -i "paramsserializer|params.*serializ" src/lib/api/resources/Repository: mailtrap/mailtrap-nodejs
Length of output: 50
Remove manual [] suffix from array parameter keys.
The code pre-suffixes array parameter keys with [] (e.g., sending_domain_ids[]), but axios.get(..., { params }) already appends [] for array values. This results in malformed query strings like sending_domain_ids[][]=... instead of the expected sending_domain_ids[]=.... The current tests only inspect the params object before serialization, so they won't catch this wire-format issue.
Fix by removing the manual [] suffix and letting Axios handle the serialization:
Proposed fix
private static buildQueryParams(
params: StatsFilterParams
): Record<string, unknown> {
const query: Record<string, unknown> = {
start_date: params.start_date,
end_date: params.end_date,
};
if (params.sending_domain_ids) {
- query["sending_domain_ids[]"] = params.sending_domain_ids;
+ query.sending_domain_ids = params.sending_domain_ids;
}
if (params.sending_streams) {
- query["sending_streams[]"] = params.sending_streams;
+ query.sending_streams = params.sending_streams;
}
if (params.categories) {
- query["categories[]"] = params.categories;
+ query.categories = params.categories;
}
if (params.email_service_providers) {
- query["email_service_providers[]"] = params.email_service_providers;
+ query.email_service_providers = params.email_service_providers;
}
return query;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/api/resources/Stats.ts` around lines 100 - 121, The buildQueryParams
method is manually appending "[]" to array parameter keys (e.g.,
"sending_domain_ids[]") which causes double-bracketed query strings when Axios
serializes arrays; update Stats.buildQueryParams (accepting StatsFilterParams)
to use plain keys ("sending_domain_ids", "sending_streams", "categories",
"email_service_providers") without the "[]" suffix so axios.get(..., { params:
buildQueryParams(...) }) will serialize arrays correctly.
Motivation
/api/accounts/{account_id}/stats) to the Node.js SDK, enabling users to retrieve aggregated email sending statistics.Changes
How to test
Examples
Summary by CodeRabbit
New Features
Tests
Chores