Skip to content

🛠️ DX: Support URL extraction for user APIs#209

Open
bartholomej wants to merge 1 commit into
masterfrom
dx/extract-user-6842156183414163731
Open

🛠️ DX: Support URL extraction for user APIs#209
bartholomej wants to merge 1 commit into
masterfrom
dx/extract-user-6842156183414163731

Conversation

@bartholomej

@bartholomej bartholomej commented Jun 25, 2026

Copy link
Copy Markdown
Owner

💡 What:
Introduced an extractUser helper to userRatings and userReviews APIs. Developers can now pass a full URL string (e.g., 'https://www.csfd.cz/uzivatel/admin/') or text slug (e.g., 'admin'), and the API will natively extract the correct user identifier without throwing a 404.

🎯 Why:
CSFD user endpoints can take both numeric IDs (912) and text slugs (admin). Previously, passing a full URL into csfd.userRatings('https://www.csfd.cz/uzivatel/admin/') caused the URL to be double-encoded in src/vars.ts, resulting in a 404 error. This forces the developer to manually parse URLs.
With this change, the userRatings and userReviews functions now behave smoothly and flexibly just like csfd.movie(), vastly improving the developer experience.

🚀 Examples:
Before:

await csfd.userRatings('https://www.csfd.cz/uzivatel/912-hobit/');
// Throws: "Bad response 404 for url: https://www.csfd.cz/uzivatel/https%3A%2F%2Fwww.csfd.cz%2Fuzivatel%2F912-hobit%2F/hodnoceni/"

After:

await csfd.userRatings('https://www.csfd.cz/uzivatel/912-hobit/');
// ✅ Works! Parses as "912"

await csfd.userRatings('https://www.csfd.cz/uzivatel/admin/');
// ✅ Works! Parses as "admin"

await csfd.userRatings('admin');
// ✅ Works!

PR created automatically by Jules for task 6842156183414163731 started by @bartholomej

Summary by CodeRabbit

  • New Features

    • User IDs, slugs, and profile URLs are now accepted in more places, with values automatically normalized before use.
    • Ratings and reviews pages now continue pagination using the normalized user identifier.
  • Bug Fixes

    • Added validation for invalid user inputs, with a clear error message when a user value can’t be parsed.
    • Improved handling of numeric slugs and URL-based user links.

Added an `extractUser` helper function in `src/helpers/global.helper.ts` to allow users to pass full URLs, text slugs, numeric slugs, or numbers into `csfd.userRatings()` and `csfd.userReviews()`.

Added corresponding unit tests in `tests/helpers.test.ts`.

Co-authored-by: bartholomej <5861310+bartholomej@users.noreply.github.com>
@google-labs-jules

Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Added extractUser to normalize numeric IDs, slugs, and user URLs. The user ratings and user reviews scrapers now validate the normalized value before building initial and paginated request URLs. Tests cover the new helper behavior.

Changes

User parsing normalization

Layer / File(s) Summary
Helper and tests
src/helpers/global.helper.ts, tests/helpers.test.ts
extractUser now parses numeric IDs, slugs, and user URLs; new tests cover the returned number, string, and null cases.
Ratings scraper normalization
src/services/user-ratings.service.ts
userRatings now imports extractUser, validates the normalized value, and uses it for the initial and paginated ratings URLs.
Reviews scraper normalization
src/services/user-reviews.service.ts
userReviews now imports extractUser, validates the normalized value, and uses it for the initial and paginated review URLs.

Sequence Diagram(s)

sequenceDiagram
  participant URat as UserRatingsScraper.userRatings
  participant E as extractUser
  participant URev as UserReviewsScraper.userReviews
  URat->>E: normalize user
  E-->>URat: userIdOrSlug
  URat->>URat: build initial and paginated ratings URLs
  URev->>E: normalize user
  E-->>URev: userIdOrSlug
  URev->>URev: build initial and paginated review URLs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A bunny sniffed a user trail,
A slug or number, none would fail.
(ᵔᴥᵔ)/
Ratings and reviews now hop ճիշտ and neat,
With tidy URLs and paws on repeat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is useful, but it does not follow the required template sections for Type of change, Related Issues, or Checklist. Add the required template headings and fill in Type of change, Related Issues, and Checklist items, including whether tests were added.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: adding URL extraction support for user APIs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dx/extract-user-6842156183414163731

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

Caution

This repository is currently using the Sentry GitHub App to receive Codecov PR comments. This integration will be deprecated on July 8, 2026. Please install the Codecov GitHub App to continue receiving coverage reports on your pull requests.
❌ Patch coverage is 86.66667% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.26%. Comparing base (686bd47) to head (cfa04da).

Files with missing lines Patch % Lines
src/helpers/global.helper.ts 90.00% 1 Missing and 1 partial ⚠️
src/services/user-ratings.service.ts 80.00% 1 Missing ⚠️
src/services/user-reviews.service.ts 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #209      +/-   ##
==========================================
- Coverage   98.71%   98.26%   -0.46%     
==========================================
  Files          34       34              
  Lines         781      807      +26     
  Branches      202      216      +14     
==========================================
+ Hits          771      793      +22     
- Misses         10       13       +3     
- Partials        0        1       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/services/user-ratings.service.ts (1)

25-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: hoist the duplicated normalize-and-validate block.

The same extractUser(user) + null/NaN guard appears verbatim here and in user-reviews.service.ts. A small shared helper (e.g. resolveUser(user): number | string) would keep the contract and error message in one place. The typeof userIdOrSlug === 'number' && isNaN(...) arm is effectively unreachable today since extractUser returns null (not a NaN number) for unparseable input.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/user-ratings.service.ts` around lines 25 - 28, The
normalize-and-validate logic for user input is duplicated in UserRatingsService
and user-reviews.service, so extract it into a shared helper like
resolveUser(user) that returns a validated number or string and centralizes the
error message. Update UserRatingsService to call that helper instead of
repeating extractUser(user) plus the null/NaN guard, and remove the unreachable
NaN branch since extractUser currently returns null for invalid input.
tests/helpers.test.ts (1)

70-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add negative-path coverage for extractUser.

The suite only exercises happy paths. Given the fallback behavior flagged in global.helper.ts, consider adding cases for invalid/empty input and a non-user URL to lock in the intended contract (and prevent regressions of the double-encoding fix).

💚 Example additions
   test('should return string for full url with text slug', () => {
     expect(extractUser('https://www.csfd.cz/uzivatel/admin/')).toBe('admin');
   });
+  test('should reject empty input', () => {
+    expect(extractUser('')).toBe(null);
+  });
+  test('should reject a non-user url', () => {
+    expect(extractUser('https://www.csfd.cz/film/228329-avatar/')).toBe(null);
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/helpers.test.ts` around lines 70 - 89, The extractUser test suite only
covers valid inputs, so add negative-path cases to lock in the fallback behavior
in extractUser from global.helper.ts. Extend the existing extractUser describe
block with tests for empty/invalid input and a non-user URL, and assert the
intended return values so the contract stays stable alongside the
double-encoding fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/helpers/global.helper.ts`:
- Around line 68-91: The extractUser logic in global.helper is falling back to
returning the raw input even when it looks like a URL, which later gets
double-encoded by userUrl and can produce broken links. Update the fallback in
extractUser so any userOrUrl value containing “/” returns null unless a valid
“uzivatel” slug was extracted, while keeping the existing numeric-slug and
plain-slug handling intact.

---

Nitpick comments:
In `@src/services/user-ratings.service.ts`:
- Around line 25-28: The normalize-and-validate logic for user input is
duplicated in UserRatingsService and user-reviews.service, so extract it into a
shared helper like resolveUser(user) that returns a validated number or string
and centralizes the error message. Update UserRatingsService to call that helper
instead of repeating extractUser(user) plus the null/NaN guard, and remove the
unreachable NaN branch since extractUser currently returns null for invalid
input.

In `@tests/helpers.test.ts`:
- Around line 70-89: The extractUser test suite only covers valid inputs, so add
negative-path cases to lock in the fallback behavior in extractUser from
global.helper.ts. Extend the existing extractUser describe block with tests for
empty/invalid input and a non-user URL, and assert the intended return values so
the contract stays stable alongside the double-encoding fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1edad948-e744-4178-9205-fb77b44aaa1a

📥 Commits

Reviewing files that changed from the base of the PR and between 686bd47 and cfa04da.

📒 Files selected for processing (4)
  • src/helpers/global.helper.ts
  • src/services/user-ratings.service.ts
  • src/services/user-reviews.service.ts
  • tests/helpers.test.ts

Comment on lines +68 to +91
// Check if it's a URL
if (userOrUrl.includes('/')) {
const parts = userOrUrl.split('/').filter(Boolean);
const uzivatelIndex = parts.indexOf('uzivatel');
if (uzivatelIndex !== -1 && parts.length > uzivatelIndex + 1) {
const userSlug = parts[uzivatelIndex + 1];
// If slug is numeric, return number, else return slug string
if (/^\d+-/.test(userSlug)) {
return +userSlug.split('-')[0] || null;
}
if (/^\d+$/.test(userSlug)) {
return +userSlug || null;
}
return userSlug;
}
}

// Direct numeric slug with ID prefix (e.g. "912-hobit")
if (/^\d+-/.test(userOrUrl)) {
return +userOrUrl.split('-')[0] || null;
}

// Return string slug as fallback (e.g. "admin")
return userOrUrl;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP -C3 'export const userUrl' src/vars.ts

Repository: bartholomej/node-csfd-api

Length of output: 462


Returning the raw URL in the fallback triggers double-encoding and 404 errors.

The userUrl helper constructs URLs via ${baseUrl}/uzivatel/${encodeURIComponent(user)}. When extractUser receives a URL string missing the uzivatel segment (skipping the extraction logic) and executes return userOrUrl, that full URL is passed to encodeURIComponent. This encodes the internal slashes (e.g., http:// becomes http%3A%2F%2F), creating a malformed URL that resolves to a 404.

Change the fallback to return null for strings containing / to ensure invalid inputs fail fast rather than propagating to the URL builder.

// File: src/helpers/global.helper.ts
// Currently at the end of the function:
// return userOrUrl; 

// Proposed:
if (userOrUrl.includes('/')) {
  return null; 
}
return userOrUrl;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/helpers/global.helper.ts` around lines 68 - 91, The extractUser logic in
global.helper is falling back to returning the raw input even when it looks like
a URL, which later gets double-encoded by userUrl and can produce broken links.
Update the fallback in extractUser so any userOrUrl value containing “/” returns
null unless a valid “uzivatel” slug was extracted, while keeping the existing
numeric-slug and plain-slug handling intact.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants