close
Skip to content

fix(#16066): improve type safety for query params in request utilities#16326

Open
rbalogic wants to merge 10 commits into
ohcnetwork:developfrom
rbalogic:issues/16066/type-query-param-safety
Open

fix(#16066): improve type safety for query params in request utilities#16326
rbalogic wants to merge 10 commits into
ohcnetwork:developfrom
rbalogic:issues/16066/type-query-param-safety

Conversation

@rbalogic
Copy link
Copy Markdown

@rbalogic rbalogic commented May 3, 2026

Proposed Changes

Fixes #16066

  • Add route-level query param typing support by wiring TQuery through the shared request utilities.
  • Update callApi, query, query.debounced, and query.paginated so queryParams preserve the API definition’s typed query contract.
  • Normalize inconsistent API definitions to use TQuery, and replace TReq with TBody in questionnaireResponseTemplateApi.
  • Expand a few existing query type definitions to match current caller usage surfaced by the stricter request typing.
  • Tighten related questionnaire/template typings required for the request-layer type safety update.

Tagging: @ohcnetwork/care-fe-code-reviewers

Merge Checklist

  • Add specs that demonstrate the bug or test the new feature.
  • Update product documentation.
  • Ensure that UI text is placed in I18n files.
  • Prepare a screenshot or demo video for the changelog entry and attach it to the issue.
  • Request peer reviews.
  • Complete QA on mobile devices.
  • Complete QA on desktop devices.
  • Add or update Playwright tests for related changes

Summary by CodeRabbit

  • Bug Fixes

    • Fixed default structure when creating medication response templates so created payloads use the correct default fields.
  • Refactor

    • Broadened request utilities to support richer request/query/body typing and improved paginated fetching behavior (handles non-zero offsets).
    • Tightened component prop typings for response-template management.
    • API specs now accept more optional filters and pagination fields for several endpoints.
  • Documentation

    • Updated request utility README to reflect the new query options schema.

@rbalogic rbalogic requested review from a team May 3, 2026 18:55
@rbalogic rbalogic requested a review from a team as a code owner May 3, 2026 18:55
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@github-actions github-actions Bot added the Type Changes Contains changes in typescript types label May 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a TQuery generic to ApiRoute and uses it to type queryParams across request utilities; widens request/mutate generics; strengthens paginated query typing and runtime paging; updates API specs to declare TQuery; narrows a component prop; README and JSDoc updated.

Changes

Query Parameter Type Safety System

Layer / File(s) Summary
Type System (data shape)
src/Utils/request/types.ts, src/types/...
ApiRoute<TRes,TBody,TQuery> added with optional TQuery; defaultQueryParams retyped to TQuery; new RouteQueryParams<Route>; ApiCallOptions.queryParams now RouteQueryParams<Route>.
API spec surface
src/types/emr/medicationRequest/medicationRequestApi.ts, src/types/inventory/.../supplyDeliveryApi.ts, src/types/inventory/.../supplyRequestApi.ts, src/types/questionnaire/questionnaireResponseTemplateApi.ts
Endpoint configs updated to use TQuery (renaming TQueryParams where present); medication list adds facility, ordering, status, exclude_dispense_status, limit, offset; questionnaire list makes some fields optional and expands key_filter; create/update request generic keys changed from TReqTBody.
Core utilities (implementation)
src/Utils/request/query.ts, src/Utils/request/mutate.ts
callApi, default query, query.debounced, and mutate generics widened to Route extends ApiRoute<unknown,unknown,unknown> to include TQuery; query.paginated constrained to ApiRoute<PaginatedResponse<unknown>,unknown,PaginationQueryParams> and accepts ApiCallOptions<Route> & { pageSize?, maxPages? }.
Paginated runtime logic
src/Utils/request/query.ts
PaginationQueryParams introduced; pageSize computed from options.pageSize ?? options.queryParams?.limit ?? RESULTS_PER_PAGE_LIMIT; startOffset from options.queryParams?.offset ?? 0; per-page queryParams built by spreading options.queryParams then overriding limit/offset; loop termination uses items.length + startOffset >= res.count.
Component & payload tweaks (wiring)
src/components/Questionnaire/ManageResponseTemplatesSheet.tsx, src/components/Questionnaire/QuestionTypes/MedicationRequestQuestion.tsx
ManageResponseTemplatesSheet.key_filter narrowed to a specific union literal type; buildMedicationForTemplate now returns MedicationRequestTemplateSpec (typed cast); template creation payload uses activity_definition: [] instead of service_request: [].
Docs & JSDoc
src/Utils/request/README.md, src/Utils/request/types.ts
README updated to show ApiCallOptions.queryParams uses route-specific TQuery; JSDoc added/updated for PaginatedResponse, UpsertRequest, Type, and HttpMethod.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: improving type safety for query parameters in request utilities by implementing TQuery support.
Description check ✅ Passed The description comprehensively covers proposed changes, mentions the issue being fixed, and includes a merge checklist aligned with the template; peer reviews were requested as required.
Linked Issues check ✅ Passed The PR fully addresses issue #16066 by wiring TQuery through request utilities (callApi, query, query.debounced, query.paginated) to provide type-checked query parameters at call sites.
Out of Scope Changes check ✅ Passed All changes are scoped to issue #16066: API definition updates (TQuery/TBody), request utility typing, pagination fixes, and dependent type tightening in questionnaire components are all necessary for TQuery propagation.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Utils/request/query.ts (1)

158-189: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't discard caller-supplied pagination cursors.

The new merge order makes query.paginated(..., { queryParams: { offset, limit } }) always start from 0 and pageSize, even though those fields are still part of the public options type. Any caller trying to resume from a non-zero offset will now fetch the wrong slice. Either seed the loop from the incoming offset/limit, or remove those fields from the exposed options.

Possible fix
-    const pageSize = options?.pageSize ?? RESULTS_PER_PAGE_LIMIT;
+    const pageSize =
+      options?.pageSize ??
+      options?.queryParams?.limit ??
+      RESULTS_PER_PAGE_LIMIT;
+    const startOffset = options?.queryParams?.offset ?? 0;
@@
         ...options,
         queryParams: {
           ...options?.queryParams,
           limit: pageSize,
-          offset: page * pageSize,
+          offset: startOffset + page * pageSize,
         } as RouteQueryParams<Route> & {
           limit?: number;
           offset?: number;
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Utils/request/query.ts` around lines 158 - 189, paginatedQuery currently
overwrites caller-supplied offset/limit; preserve them by seeding the loop from
options.queryParams: compute a startingOffset = options?.queryParams?.offset ??
0 and set pageSize = options?.pageSize ?? options?.queryParams?.limit ??
RESULTS_PER_PAGE_LIMIT, initialize page = Math.floor(startingOffset / pageSize)
(or 0) and then pass offset = startingOffset + page * pageSize and limit =
pageSize into the per-iteration query call so callers can resume from a non-zero
offset while pageSize still defaults to RESULTS_PER_PAGE_LIMIT when neither
option is provided.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/Utils/request/query.ts`:
- Around line 158-189: paginatedQuery currently overwrites caller-supplied
offset/limit; preserve them by seeding the loop from options.queryParams:
compute a startingOffset = options?.queryParams?.offset ?? 0 and set pageSize =
options?.pageSize ?? options?.queryParams?.limit ?? RESULTS_PER_PAGE_LIMIT,
initialize page = Math.floor(startingOffset / pageSize) (or 0) and then pass
offset = startingOffset + page * pageSize and limit = pageSize into the
per-iteration query call so callers can resume from a non-zero offset while
pageSize still defaults to RESULTS_PER_PAGE_LIMIT when neither option is
provided.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3b04e2b9-095d-42f6-89e4-a313703d3f07

📥 Commits

Reviewing files that changed from the base of the PR and between f17b61b and 804a2b0.

📒 Files selected for processing (10)
  • src/Utils/request/README.md
  • src/Utils/request/mutate.ts
  • src/Utils/request/query.ts
  • src/Utils/request/types.ts
  • src/components/Questionnaire/ManageResponseTemplatesSheet.tsx
  • src/components/Questionnaire/QuestionTypes/MedicationRequestQuestion.tsx
  • src/types/emr/medicationRequest/medicationRequestApi.ts
  • src/types/inventory/supplyDelivery/supplyDeliveryApi.ts
  • src/types/inventory/supplyRequest/supplyRequestApi.ts
  • src/types/questionnaire/questionnaireResponseTemplateApi.ts

@rbalogic
Copy link
Copy Markdown
Author

rbalogic commented May 3, 2026

I have addressed the feedback provided by CodeRabbit regarding docstring coverage, pagination logic, and the scope of changes.

1. Fixed Pagination Cursor Handling (✅ Resolved)

As identified in the detailed review of src/Utils/request/query.ts, query.paginated was previously discarding caller-supplied offset and limit values.

  • Refactored Logic: The utility now uses options.queryParams.offset as the starting point (startOffset) and options.queryParams.limit as the default pageSize.
  • Offset Computation: The pagination loop now correctly computes subsequent offsets as startOffset + page * pageSize.
  • Benefit: This allows callers to resume or start from any point while still benefiting from automatic multi-page fetching.

2. Improved Docstring Coverage (✅ Fixed)

I have added comprehensive TSDoc comments to the core request utility layer to meet the 80% threshold:

  • src/Utils/request/types.ts: Documented all exported types (ApiRoute, ApiCallOptions, PaginatedResponse, etc.).
  • src/Utils/request/query.ts: Added detailed documentation for callApi, query.debounced, and query.paginated.

3. Clarification on "Out of Scope" Changes

The changes flagged as out-of-scope are essential dependencies for the TQuery type-safety system:

  • Prop Type Narrowing (ManageResponseTemplatesSheet): Required to align with the updated questionnaireResponseTemplateApi.list endpoint.
  • Template Data Structure (MedicationRequestQuestion): Necessary to match the underlying schema changes in the Questionnaire API (service_requestactivity_definition).
  • Normalization (TReq to TBody): Standardized naming across API definitions to ensure reliable generic type inference within the ApiRoute interface.

@github-actions github-actions Bot added needs-triage question Further information is requested labels May 3, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Utils/request/query.ts (1)

168-199: ⚠️ Potential issue | 🟠 Major

paginatedQuery should enforce pagination parameters in the route's TQuery constraint.

The function currently accepts any route returning PaginatedResponse regardless of whether its TQuery includes limit and offset. Inside the loop (line ~197), it casts the constructed query params to bypass the type check, which sidesteps the contract from types.ts. This allows a route with a restrictive custom TQuery (e.g., { request_order: string }) to compile with paginatedQuery, even though pagination params aren't declared.

While current usage is safe (routes with custom TQuery are never used with paginatedQuery), the type system should prevent this at compile time.

Suggested fix
 import {
   ApiCallOptions,
   ApiRoute,
   HTTPError,
   PaginatedResponse,
+  QueryParams,
   RouteQueryParams,
 } from "@/Utils/request/types";
+
+interface PaginationQueryParams extends QueryParams {
+  limit?: number;
+  offset?: number;
+}
@@
 const paginatedQuery = <
-  Route extends ApiRoute<PaginatedResponse<unknown>, unknown, unknown>,
+  Route extends ApiRoute<
+    PaginatedResponse<unknown>,
+    unknown,
+    PaginationQueryParams
+  >,
 >(
@@
         queryParams: {
           ...options?.queryParams,
           limit: pageSize,
           offset: page * pageSize,
-        } as RouteQueryParams<Route> & {
-          limit?: number;
-          offset?: number;
-        },
+        },
       })({ signal });

Per coding guidelines: "Always provide proper TypeScript types for parameters and return values in utility functions" and "Use generic types where appropriate for reusability in utility functions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Utils/request/query.ts` around lines 168 - 199, paginatedQuery currently
accepts any ApiRoute that returns PaginatedResponse but bypasses TQuery typing
by casting query params; change the generic so the Route's TQuery is constrained
to include optional pagination fields and stop using the cast. Specifically,
introduce a generic for the route query (e.g., Q extends RouteQueryParams<Route>
& { limit?: number; offset?: number } or directly constrain Route as Route
extends ApiRoute<PaginatedResponse<unknown>, Record<string, unknown> & { limit?:
number; offset?: number }, unknown>), update the paginatedQuery signature to use
that constrained Route type, and then remove the "as RouteQueryParams..." cast
when passing queryParams to query(route, {...}) so the compiler enforces routes
declare limit/offset. Reference symbols: paginatedQuery, ApiRoute,
RouteQueryParams, TQuery/TRes, and query.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Utils/request/types.ts`:
- Around line 24-40: The ApiRoute generic should constrain TQuery so routes
cannot widen to a plain QueryParams; update the ApiRoute declaration so the
TQuery generic is declared as TQuery extends QueryParams = QueryParams and
change the defaultQueryParams property to be typed as TQuery
(defaultQueryParams?: TQuery) so any provided defaults must conform to the
route's declared query shape; update any related uses of ApiRoute/TQuery to
respect the new constraint.

---

Outside diff comments:
In `@src/Utils/request/query.ts`:
- Around line 168-199: paginatedQuery currently accepts any ApiRoute that
returns PaginatedResponse but bypasses TQuery typing by casting query params;
change the generic so the Route's TQuery is constrained to include optional
pagination fields and stop using the cast. Specifically, introduce a generic for
the route query (e.g., Q extends RouteQueryParams<Route> & { limit?: number;
offset?: number } or directly constrain Route as Route extends
ApiRoute<PaginatedResponse<unknown>, Record<string, unknown> & { limit?: number;
offset?: number }, unknown>), update the paginatedQuery signature to use that
constrained Route type, and then remove the "as RouteQueryParams..." cast when
passing queryParams to query(route, {...}) so the compiler enforces routes
declare limit/offset. Reference symbols: paginatedQuery, ApiRoute,
RouteQueryParams, TQuery/TRes, and query.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8557dc3d-12cb-4881-8e86-7de8e3301227

📥 Commits

Reviewing files that changed from the base of the PR and between 804a2b0 and c6d51c6.

📒 Files selected for processing (2)
  • src/Utils/request/query.ts
  • src/Utils/request/types.ts

Comment thread src/Utils/request/types.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Utils/request/query.ts`:
- Around line 193-197: The type for the options parameter can be simplified by
removing the redundant Omit and explicit re-declaration of queryParams: replace
the current "Omit<ApiCallOptions<Route>, 'queryParams'> & { queryParams?:
RouteQueryParams<Route>; pageSize?: number; maxPages?: number }" with
"ApiCallOptions<Route> & { pageSize?: number; maxPages?: number }" so you keep
ApiCallOptions and its existing queryParams typing (RouteQueryParams<Route>)
while adding pageSize and maxPages; update the type where the parameter named
options is declared to reference ApiCallOptions<Route> & { pageSize?: number;
maxPages?: number } (look for the options type definition around the function
that uses ApiCallOptions and RouteQueryParams).
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1eb885c7-dc9f-4472-8dc3-68794eb36e68

📥 Commits

Reviewing files that changed from the base of the PR and between 682e16f and 43207f1.

📒 Files selected for processing (2)
  • src/Utils/request/query.ts
  • src/Utils/request/types.ts

Comment thread src/Utils/request/query.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Utils/request/query.ts`:
- Around line 203-207: In query.paginated, validate and normalize pagination
inputs before the paging loop: ensure pageSize (computed from options?.pageSize
or options?.queryParams?.limit or RESULTS_PER_PAGE_LIMIT) is a positive integer
(if <= 0 either throw a clear error or default it to RESULTS_PER_PAGE_LIMIT) and
ensure startOffset (from options?.queryParams?.offset) is >= 0 (coerce negatives
to 0 or throw). Use the validated/normalized pageSize and startOffset variables
in the loop (the code that advances offset by pageSize) so the offset always
progresses and invalid values cannot cause an infinite loop or invalid API
requests.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7cac2731-6106-4712-bec9-d02f9e43763b

📥 Commits

Reviewing files that changed from the base of the PR and between 43207f1 and 427ef3a.

📒 Files selected for processing (1)
  • src/Utils/request/query.ts

Comment thread src/Utils/request/query.ts Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

🚀 Preview Deployment Ready!

🔗 Preview URL: https://pr-16326.care-preview-a7w.pages.dev

📱 Mobile Access:
Scan the QR code below to open the preview on your mobile device.

QR Code


This preview will be automatically updated when you push new commits to this PR.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

🎭 Playwright Test Results

Status: ❌ Failed
Test Shards: 3

Metric Count
Total Tests 288
✅ Passed 287
❌ Failed 1
⏭️ Skipped 0

📊 Detailed results are available in the playwright-final-report artifact.

Run: #8756

@parvathyns-creator
Copy link
Copy Markdown

@nihal467 this looks fine

@netlify
Copy link
Copy Markdown

netlify Bot commented May 16, 2026

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit e832a54
🔍 Latest deploy log https://app.netlify.com/projects/care-ohc/deploys/6a0c88b36d735500085fc278
😎 Deploy Preview https://deploy-preview-16326.preview.ohc.network
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@rbalogic
Copy link
Copy Markdown
Author

Hi @gigincg, @nihal467, @bodhish, and @rithviknishad!

Just following up on this PR when you have a moment. As a first-time contributor to the project, I'd love to get your feedback and make any necessary adjustments to get this merged.

Thank you for your time and for maintaining this project! 🙌

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

Labels

needs review needs testing needs-triage question Further information is requested Type Changes Contains changes in typescript types

Projects

None yet

Development

Successfully merging this pull request may close these issues.

improve type safety for query params in data fetching utility fn's using TQuery

2 participants