Skip to content

Remove axios dependency and replace with native fetch in web-ui#7386

Open
aajisaka wants to merge 1 commit intoapache:masterfrom
aajisaka:remove-axios
Open

Remove axios dependency and replace with native fetch in web-ui#7386
aajisaka wants to merge 1 commit intoapache:masterfrom
aajisaka:remove-axios

Conversation

@aajisaka
Copy link
Copy Markdown
Member

@aajisaka aajisaka commented Apr 6, 2026

Why are the changes needed?

Replace axios with the native Fetch API in request.ts, removing the axios dependency from package.json. Reducing the dependent libraries to reduce the possibility of supply chain attack and to reduce future maintenance cost. Enforce Node.js >=18 via the engines field and update README accordingly.

How was this patch tested?

Covered by the existing unit tests.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Claude Opus 4.6)

Replace axios with the native Fetch API in request.ts, removing the
axios dependency from package.json. Enforce Node.js >=18 via the
engines field and update README accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added kind:infra license, community building, project builds, asf infra related, etc. module:ui labels Apr 6, 2026
@pan3793
Copy link
Copy Markdown
Member

pan3793 commented Apr 10, 2026

Review comments from Claude Code

  Issues and Suggestions

  Bug: Behavioral difference in error handling (Medium severity)

  The current axios implementation rejects the promise on non-2xx errors but still dispatches the auth-required event for 401s. The new fetch implementation throws for 401 but also throws a generic Error for all
  other non-OK responses.

  The key difference: the old axios interceptor returns response.data for ALL successful responses, including those with response.data.code === 503. The new implementation returns undefined for non-JSON responses.
  This is fine for the current API, but worth noting.

  More importantly, the old code's error path was:
  // axios: error.response exists, caller catches an AxiosError with .response property
  return Promise.reject(error)
  The new code throws a plain Error('HTTP error! status: ...'). If any caller inspects the error shape (e.g., error.response.status), this would break. From my review of the callers, none do — but it's worth
  verifying manually.

  Bug: baseURL is not carried over (Medium severity)

  The old axios instance was configured with baseURL: '/'. The new fetch implementation uses relative URLs directly (e.g., fetch('api/v1/sessions')). In a browser, relative URLs resolve against window.location,
  which works if the app is served from the root. But the Vite config sets base: '/ui/', which means in production the app is served under /ui/.

  Relative fetch('api/v1/sessions') from a page at /ui/ would resolve to /ui/api/v1/sessions, not /api/v1/sessions. With axios, baseURL: '/' ensures all requests go to /<url> regardless of the page path.

  This is likely a bug. The new request.ts should prepend '/' to ensure absolute path resolution:
  let fullUrl = url.startsWith('/') ? url : `/${url}`

  Suggestion: Handle empty response body gracefully

  The implementation checks content-type to decide whether to parse JSON:
  const contentType = response.headers.get('content-type')
  if (!contentType || !contentType.includes('application/json')) {
    return undefined
  }
  return response.json()

  If the server returns 204 No Content with a JSON content-type header (or 200 with an empty body), response.json() will throw. Consider:
  const text = await response.text()
  return text ? JSON.parse(text) : undefined
  This is defensive but costs almost nothing.

  Suggestion: RequestConfig.method should be typed more strictly

  method: string  // current
  method: 'get' | 'post' | 'put' | 'delete'  // better
  Since all callers use these four methods, a union type catches typos at compile time.

  Nit: params serialization edge case

  URLSearchParams.append(key, String(value)) will serialize arrays as their string representation (e.g., "1,2,3"). The current axios implementation serializes array params differently (repeated keys:
  key=1&key=2&key=3). From the codebase, the params objects passed are simple key-value pairs, so this shouldn't matter today — but it's a behavioral difference to document.

  Nit: Missing the response.data.code === 503 handler

  The old interceptor had a (commented/empty) case for response.data.code === 503. It was a no-op, so dropping it is fine, but worth mentioning for completeness.

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

Labels

kind:infra license, community building, project builds, asf infra related, etc. module:ui

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants