Make API URL dynamic based on hostname
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
- localhost/127.0.0.1 → http://localhost:8000/api/v1 - Local network IPs → http://{hostname}:8000/api/v1 - Production domains → https://{hostname}/api/v1 (requires reverse proxy)
This commit is contained in:
@ -1,20 +1,44 @@
|
||||
/**
|
||||
* API client for pounce backend
|
||||
*
|
||||
* API URL is determined dynamically based on the current hostname:
|
||||
* - localhost/127.0.0.1 → http://localhost:8000/api/v1
|
||||
* - Local network IPs (10.x, 192.168.x) → http://{hostname}:8000/api/v1
|
||||
* - Production (any other domain) → https://{hostname}/api/v1 (requires reverse proxy)
|
||||
*/
|
||||
|
||||
// Ensure API_BASE ends with /api/v1 and no trailing slash
|
||||
const getApiBase = () => {
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
|
||||
// Remove trailing slash if present
|
||||
const cleanBase = baseUrl.replace(/\/$/, '')
|
||||
// Add /api/v1 if not present
|
||||
if (cleanBase.endsWith('/api/v1')) {
|
||||
return cleanBase
|
||||
const getApiBase = (): string => {
|
||||
// Server-side rendering: use environment variable or localhost
|
||||
if (typeof window === 'undefined') {
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1'
|
||||
return baseUrl.replace(/\/$/, '')
|
||||
}
|
||||
return `${cleanBase}/api/v1`
|
||||
|
||||
const { protocol, hostname, port } = window.location
|
||||
|
||||
// Localhost development
|
||||
if (hostname === 'localhost' || hostname === '127.0.0.1') {
|
||||
return 'http://localhost:8000/api/v1'
|
||||
}
|
||||
|
||||
// Local network (10.x.x.x, 192.168.x.x, 172.16-31.x.x)
|
||||
if (/^(10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)/.test(hostname)) {
|
||||
return `http://${hostname}:8000/api/v1`
|
||||
}
|
||||
|
||||
// Production: use same protocol and domain with /api/v1 path
|
||||
// This requires a reverse proxy (nginx/caddy) to route /api/v1 to the backend
|
||||
return `${protocol}//${hostname}/api/v1`
|
||||
}
|
||||
|
||||
const API_BASE = getApiBase()
|
||||
// Lazy-evaluated to ensure window is available on client
|
||||
let _apiBase: string | null = null
|
||||
const getApiBaseUrl = (): string => {
|
||||
if (_apiBase === null) {
|
||||
_apiBase = getApiBase()
|
||||
}
|
||||
return _apiBase
|
||||
}
|
||||
|
||||
interface ApiError {
|
||||
detail: string
|
||||
@ -44,7 +68,7 @@ class ApiClient {
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const url = `${API_BASE}${endpoint}`
|
||||
const url = `${getApiBaseUrl()}${endpoint}`
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers as Record<string, string>,
|
||||
|
||||
Reference in New Issue
Block a user