Skip to content

Cleanup HTTP client headers and testing code#55

Open
cyrossignol wants to merge 2 commits into
masterfrom
cleanup-headers
Open

Cleanup HTTP client headers and testing code#55
cyrossignol wants to merge 2 commits into
masterfrom
cleanup-headers

Conversation

@cyrossignol
Copy link
Copy Markdown
Collaborator

@cyrossignol cyrossignol commented May 28, 2026

This cleans up the abstraction for HTTP request header configuration in the various API clients by merging headers instead of overwriting them.

This also cleans up some old HTTP testing code which resolves some potential auth token refresh issues in TDEI calls.

Summary

This PR refactors HTTP client header handling across the frontend services to merge headers instead of overwriting them, and removes legacy testing code. The changes introduce type-safe configurations for HTTP requests and centralize header management in the base HTTP client.

Changes by File

services/http.ts

  • Added exported types FetchConfig (based on RequestInit with optional typed headers) and HttpBody (union of BodyInit | object)
  • Refactored BaseHttpClient._send pipeline to merge default headers with per-request headers from FetchConfig
  • Improved body handling: FormData strips the Content-Type header to allow browser defaults, and JSON stringification is determined by both resolved Content-Type and runtime body type
  • Removed the _sendTest helper method, simplifying the test code cleanup
  • Updated all request method signatures (_get, _post, _put, _patch, _delete) to use the new FetchConfig type

services/osm.ts

  • Updated method signature for _send override to use typed HttpBody and FetchConfig parameters
  • Changed default Accept header from text/plain to */*
  • Refactored provisionUser to pass JSON objects directly with Content-Type: application/json instead of manually stringifying
  • Removed per-request spreading of internal _requestHeaders across multiple methods (workspace/element/node/way retrieval, changeset operations, notes search, export)
  • Centralized auth handling: _send override now calls tryRefreshAuth() before sending and re-applies auth headers via #setAuthHeader(), then merges credentials: 'include' with provided config

services/tdei.ts

  • Updated _send override signatures in both TdeiClient and TdeiUserClient to use typed HttpBody and FetchConfig parameters
  • Replaced _sendTest calls with _get for dataset downloads (downloadOswDataset, downloadPathwaysDataset)
  • Removed explicit per-request Authorization header injection from upload methods
  • Simplified dataset conversion flow by removing manual Accept/Authorization header handling
  • Preserved refresh-before-send behavior in both client classes

services/workspaces.ts

  • Updated WorkspacesClient._send method signature to use typed HttpBody and FetchConfig parameters instead of loose types
  • Runtime behavior preserved: auth refresh, header setting, and error wrapping remain unchanged

Key Improvements

  • Centralized header merging logic prevents accidental header overwriting
  • Type-safe HTTP configuration across all services
  • Removal of _sendTest test helper reduces code duplication
  • Consistent auth token refresh handling, addressing potential token refresh issues in TDEI calls

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

This PR consolidates HTTP request handling across the codebase by introducing type-safe request configuration, refactoring the core HTTP client to merge headers centrally, and migrating all API clients (OSM, TDEI, Workspaces) to use the new standardized types and header management patterns.

Changes

HTTP Client Request Handling Consolidation

Layer / File(s) Summary
HTTP types and BaseHttpClient refactoring
services/http.ts
Introduces HttpBody and FetchConfig types. Refactors _get, _post, _put, _patch, _delete, and _send to accept typed parameters. Core _send pipeline now merges default and per-request headers, special-cases FormData by removing Content-Type, and expands JSON-stringification conditions. Removes _sendTest helper.
OSM API client migration
services/osm.ts
Updates imports to use HttpBody and FetchConfig. Changes default Accept header from text/plain to */*. Simplifies all request methods (provisionUser, getElement, getNodes, getWays, listChangesets, getChangeset, getOsmChange, createChangeset, uploadChangeset, postChangesetComment, getNotes, getWorkspaceData, exportWorkspaceXml) to remove spreading of _requestHeaders and manual Authorization injection. Refactors _send override to refresh auth, re-apply auth headers, merge credentials: 'include', and delegate to BaseHttpClient.
TDEI client migration
services/tdei.ts
Updates imports to use HttpBody and FetchConfig. Replaces _sendTest(..., 'GET') calls with _get(...) and explicit Accept: '*/*' headers in dataset download methods. Removes manual Authorization header injection from upload and conversion methods. Updates TdeiClient and TdeiUserClient _send overrides to use typed parameters and unknown catch, preserving refresh-before-send behavior.
Workspaces client migration
services/workspaces.ts
Updates import to include HttpBody and FetchConfig types. Tightens _send override method parameter types from untyped (any/object) to HttpBody and FetchConfig, while preserving refresh-auth, set-auth-header, and super._send call flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through headers with care,
Centralizing requests with flair!
Types now guide the way,
Auth flows cleaner each day,
HTTP dreams float through the air. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: refactoring HTTP client headers to merge instead of overwrite, and removing the _sendTest testing helper.
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.

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.

services/http.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

services/osm.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

services/tdei.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.

  • 1 others

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

@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: 2

🤖 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 `@services/osm.ts`:
- Around line 521-535: The _send method can reuse a stale Authorization header
because `#setAuthHeader` only adds a header when auth exists but never removes an
old one; update the code so that before calling `#setAuthHeader` (or inside
`#setAuthHeader`) you explicitly remove any existing Authorization header when
there is no current token — for example, clear this.headers['authorization'] (or
call a new clearAuthHeader helper) if `#tdeiClient.tryRefreshAuth` indicates auth
is not present, then only set the header when a fresh token is available; make
this change in the _send flow (and optionally in `#setAuthHeader`) to ensure stale
bearer values are not sent.

In `@services/tdei.ts`:
- Around line 429-440: refreshToken() can clear this.#auth but headers may still
contain a stale Authorization value when _send() forwards the request; before
calling super._send(url, method, body, config) explicitly sync the Authorization
header to current this.#auth (set it when present, remove/clear it when auth is
empty) so no stale bearer is sent, and apply the same header-sync logic at the
other send path referenced (the second _send call site).
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ea4a8759-b770-4d35-8ac8-23510a92af8f

📥 Commits

Reviewing files that changed from the base of the PR and between d41aec5 and faec03d.

📒 Files selected for processing (4)
  • services/http.ts
  • services/osm.ts
  • services/tdei.ts
  • services/workspaces.ts

Comment thread services/osm.ts
Comment on lines +521 to 535
override async _send(
url: string,
method: string,
body?: HttpBody,
config?: FetchConfig,
): Promise<Response> {
try {
await this.#tdeiClient.tryRefreshAuth();
this.#setAuthHeader();

const requestOptions = {
credentials: 'include'
}
const requestOptions: FetchConfig = {
credentials: 'include',
};

return await super._send(url, method, body, { ...requestOptions, ...config });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear stale Authorization header before sending requests.

On Line 529, _send reuses #setAuthHeader(), but that helper only writes when auth is complete and never clears an old token. After auth is cleared, this can keep sending a stale bearer value.

Suggested fix
  `#setAuthHeader`() {
-    if (this.#tdeiClient.auth.complete) {
-      this._requestHeaders.Authorization = 'Bearer ' + this.#tdeiClient.auth.accessToken;
-    }
+    this._requestHeaders.Authorization = this.#tdeiClient.auth.complete
+      ? `Bearer ${this.#tdeiClient.auth.accessToken}`
+      : '';
  }
🤖 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 `@services/osm.ts` around lines 521 - 535, The _send method can reuse a stale
Authorization header because `#setAuthHeader` only adds a header when auth exists
but never removes an old one; update the code so that before calling
`#setAuthHeader` (or inside `#setAuthHeader`) you explicitly remove any existing
Authorization header when there is no current token — for example, clear
this.headers['authorization'] (or call a new clearAuthHeader helper) if
`#tdeiClient.tryRefreshAuth` indicates auth is not present, then only set the
header when a fresh token is available; make this change in the _send flow (and
optionally in `#setAuthHeader`) to ensure stale bearer values are not sent.

Comment thread services/tdei.ts
Comment on lines +429 to 440
override async _send(
url: string,
method: string,
body?: HttpBody,
config?: FetchConfig,
): Promise<Response> {
try {
if (this.#auth.needsRefresh) {
await this.refreshToken();
}

return await super._send(url, method, body, config);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resync Authorization header on every send and clear it when auth is empty.

refreshToken() can clear auth on Line 195, but requests at Line 440/Line 536 may still carry a stale bearer because the header helpers never clear old values. Please make header sync explicit before dispatch.

Suggested fix
  `#setAuthHeader`() {
-    if (this.#auth.complete) {
-      this._requestHeaders.Authorization = 'Bearer ' + this.#auth.accessToken;
-    }
+    this._requestHeaders.Authorization = this.#auth.complete
+      ? `Bearer ${this.#auth.accessToken}`
+      : '';
  }

  override async _send(
    url: string,
    method: string,
    body?: HttpBody,
    config?: FetchConfig,
  ): Promise<Response> {
    try {
      if (this.#auth.needsRefresh) {
        await this.refreshToken();
      }
+      this.#setAuthHeader();
      return await super._send(url, method, body, config);
    }
    catch (e: unknown) {
      ...
    }
  }

  `#setAuthHeader`() {
-    if (this.#auth.complete) {
-      this._requestHeaders.Authorization = 'Bearer ' + this.#auth.accessToken;
-    }
+    this._requestHeaders.Authorization = this.#auth.complete
+      ? `Bearer ${this.#auth.accessToken}`
+      : '';
  }

Also applies to: 526-537

🤖 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 `@services/tdei.ts` around lines 429 - 440, refreshToken() can clear this.#auth
but headers may still contain a stale Authorization value when _send() forwards
the request; before calling super._send(url, method, body, config) explicitly
sync the Authorization header to current this.#auth (set it when present,
remove/clear it when auth is empty) so no stale bearer is sent, and apply the
same header-sync logic at the other send path referenced (the second _send call
site).

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.

1 participant