Skip to content

Commit 0c27551

Browse files
Cawlummclaude
andauthored
fix: resolve API base URL per-request so Server Settings takes effect (#20)
* fix: resolve API base URL per-request so Server Settings takes effect The axios baseURL was frozen at module-load time, so changing the server via the Server Settings panel had no effect until a full page reload — requests kept hitting the stale base and failed silently with no response, surfacing as a generic "Registration failed" (issue #14). Resolve the base URL in the request interceptor instead, and fix the wrong API path in web/.env.example (/api -> /api/v1). https://claude.ai/code/session_0136mFAkQRJoTASLsyFEW42L * chore: gitignore .playwright-mcp/ artifact dir Playwright MCP server writes snapshots/console logs/screenshots to .playwright-mcp/ during interactive QA. Untracked test artifact, not source. Group with the existing Playwright ignore block. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b5b9dab commit 0c27551

3 files changed

Lines changed: 12 additions & 7 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@ CLAUDE.md
5757
# Playwright artifacts
5858
web/e2e/.auth/
5959
web/test-results/
60+
.playwright-mcp/

web/.env.example

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
# API Configuration
2-
VITE_API_URL=http://localhost:3000/api
1+
# API Configuration — optional.
2+
# Leave unset for the standard deploy (nginx proxies /api to the backend).
3+
# If set, it must be the full API base including the version segment.
4+
# VITE_API_URL=http://localhost:3000/api/v1

web/src/services/api.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import axios, { AxiosInstance } from 'axios'
22
import * as types from '../types'
33

4-
const getAPIBase = () => {
4+
// Resolved per-request so the "Server settings" panel takes effect immediately,
5+
// without needing a full page reload.
6+
const resolveAPIBase = () => {
7+
const envUrl = import.meta.env.VITE_API_URL as string | undefined
8+
if (envUrl) return envUrl
59
const serverUrl = localStorage.getItem('server_url')
610
return serverUrl ? `${serverUrl}/api/v1` : '/api/v1'
711
}
812

9-
const API_BASE = (import.meta.env.VITE_API_URL as string) || getAPIBase()
10-
1113
const api: AxiosInstance = axios.create({
12-
baseURL: API_BASE,
1314
headers: { 'Content-Type': 'application/json' },
1415
})
1516

1617
api.interceptors.request.use((config) => {
18+
config.baseURL = resolveAPIBase()
1719
const token = localStorage.getItem('access_token')
1820
if (token) config.headers.Authorization = `Bearer ${token}`
1921
return config
@@ -27,7 +29,7 @@ api.interceptors.response.use(
2729
original._retry = true
2830
try {
2931
const refreshToken = localStorage.getItem('refresh_token')
30-
const res = await axios.post(`${API_BASE}/auth/refresh`, { refresh_token: refreshToken })
32+
const res = await axios.post(`${resolveAPIBase()}/auth/refresh`, { refresh_token: refreshToken })
3133
const newToken = res.data.data.token
3234
localStorage.setItem('access_token', newToken)
3335
original.headers.Authorization = `Bearer ${newToken}`

0 commit comments

Comments
 (0)