Theme Library API Base URL Fix
Fixed critical issue where ThemeHttpStorageService was calling the frontend instead of the backend
Theme Library API Base URL Fix
Critical Bug Found
The Theme Library was showing "No global themes retrieved yet" because ThemeHttpStorageService was making requests to the frontend URL instead of the backend API!
The Problem
Error in Browser Console:
🚨 HTTP API Error getting all themes: HttpErrorResponse {
status: 200,
statusText: 'OK',
url: 'http://localhost:5701/api/themes', // ❌ WRONG - Frontend!
ok: false
}
Expected URL:
http://localhost:3000/api/themes // ✅ Correct - Backend!
Root Cause
ThemeHttpStorageService was using relative URLs (/api/themes) which Angular resolved relative to the current page origin (frontend port 5701), not the backend port (3000).
// ❌ BEFORE: Relative URL (resolves to frontend)
this.http.get('/api/themes')
// Results in: http://localhost:5701/api/themes (WRONG!)
The frontend doesn't have a /api/themes endpoint, so it returned the Angular app HTML (200 OK), which failed to parse as JSON, causing the error.
Why Other Services Worked
Other services like SpaceApiService were already injecting API_BASE_URL and using absolute URLs:
// ✅ SpaceApiService (working correctly)
export class SpaceApiService {
private readonly baseUrl = inject(API_BASE_URL); // Gets 'http://localhost:3000/api'
getCurrentSpace(): Observable<Space> {
return this.http.get(`${this.baseUrl}/spaces/me`);
// Results in: http://localhost:3000/api/spaces/me (CORRECT!)
}
}
The Fix
File: libs/theme-system/theme-runtime/src/lib/api/theme-http-storage.service.ts
- Import API_BASE_URL token:
import { API_BASE_URL } from '@libs-foundational/core-angular';
- Inject the base URL:
export class ThemeHttpStorageService {
private readonly http = inject(HttpClient);
private readonly logger = inject(ThemeLoggerService);
private readonly baseUrl = inject(API_BASE_URL); // ✅ NEW
}
- Use absolute URLs in all methods:
// ✅ AFTER: Absolute URL using injected baseUrl
getAllThemes(): Observable<Theme[]> {
const url = `${this.baseUrl}/themes`; // http://localhost:3000/api/themes
return this.http.get<{status: number; data: Theme[]}>(url).pipe(...)
}
Updated Methods
All HTTP methods were updated to use ${this.baseUrl}/themes:
- ✅
getAllThemes()-GET ${baseUrl}/themes - ✅
saveTheme()-POST ${baseUrl}/themes - ✅
getActiveThemeId()-GET ${baseUrl}/themes/active - ✅
setActiveThemeId()-PUT ${baseUrl}/themes/active - ✅
validateTheme()-POST ${baseUrl}/themes/validate - ✅
exportThemes()-POST ${baseUrl}/themes/export - ✅
importThemes()-POST ${baseUrl}/themes/import - ✅
clearAllThemes()-DELETE ${baseUrl}/themes - ✅
checkHealth()-GET ${baseUrl}/themes
Files Modified
libs/theme-system/theme-runtime/src/lib/api/theme-http-storage.service.ts- Added
API_BASE_URLinjection - Updated all HTTP calls to use
${this.baseUrl}/themes - Fixed 9 methods total
- Added
apis/backend-api/src/app/themes/themes.controller.ts(from previous fix)- Made GET endpoints public (no auth required)
apis/backend-api/src/app/spaces/spaces.service.ts(from previous fix)- Fixed date format consistency
apis/backend-api/src/app/themes/themes.service.ts(from previous fix)- Enhanced logging
Testing
1. Wait for Frontend Recompile
The frontend should automatically detect the changes and recompile. Watch Terminal 1 for:
Application bundle generation complete. [X.XXX seconds]
Component update sent to client(s).
2. Refresh Browser
- Press F5 to refresh the page
- Or hard refresh: Cmd+Shift+R (Mac) / Ctrl+Shift+R (Windows)
3. Open Developer Console
Press F12 and check for these logs:
✅ Success Logs:
🎨 [DEBUG] ThemeHttpStorageService.getAllThemes() called, URL: http://localhost:3000/api/themes
🎨 [DEBUG] GET themes response: {status: 200, data: Array(4)}
✅ [DEBUG] Found 4 themes, data: [...]
4. Navigate to Theme Library
- Go to Theme Designer
- Click "Theme Library" button
- Expected: You should now see 4 themes displayed!
5. Verify in Network Tab
- Open DevTools → Network tab
- Navigate to Theme Library
- Look for the request to
themes - Expected Request URL:
http://localhost:3000/api/themes✅ - Expected Status: 200 OK
- Expected Response: JSON with
{status: 200, data: [...]}
How API_BASE_URL Works
The API_BASE_URL injection token is configured in apps/gograb-space/src/app/app.config.ts:
// Provided in app.config.ts
{
provide: API_BASE_URL,
useValue: environment.backendApiUrl // 'http://localhost:3000/api'
}
This value comes from apps/gograb-space/src/environments/environment.ts:
import { BACKEND_URLS } from './environment.shared';
export const environment = {
useMockApi: false,
backendApiUrl: BACKEND_URLS.local, // 'http://localhost:3000/api'
};
And BACKEND_URLS.local is defined in environment.shared.ts:
export const BACKEND_URLS = {
railway: 'https://backend-api-production-97c0.up.railway.app/api',
local: 'http://localhost:3000/api', // ← This value
mock: '',
};
Architecture Lessons
✅ Always Use Injection Tokens for URLs
Good Pattern (used by all other services):
export class MyService {
private readonly baseUrl = inject(API_BASE_URL);
getData() {
return this.http.get(`${this.baseUrl}/endpoint`);
}
}
Bad Pattern (what ThemeHttpStorageService was doing):
export class MyService {
getData() {
return this.http.get('/api/endpoint'); // ❌ Relative URL
}
}
Why Relative URLs Fail
When you use a relative URL like /api/themes:
- Browser resolves it relative to the current page origin
- If page is
http://localhost:5701, URL becomeshttp://localhost:5701/api/themes - This hits the frontend server, not the backend!
Why Absolute URLs with DI Work
When you use ${this.baseUrl}/themes:
baseUrlis injected fromAPI_BASE_URLtoken- Value is
http://localhost:3000/api(from environment config) - Final URL:
http://localhost:3000/api/themes✅ - This correctly hits the backend server!
Verification Checklist
- ✅ Frontend recompiles without errors
- ✅ Browser console shows debug logs with correct URL (
http://localhost:3000/api/themes) - ✅ Network tab shows request to port 3000 (not 5701)
- ✅ Response is JSON (not HTML)
- ✅ Theme Library displays 4 themes
- ✅ No linter errors
Related Fixes
This fix is part of a series to get the Theme Library working:
- Auth Fix (
THEME_LIBRARY_FIX.md) - Made GET endpoints public - Date Format Fix (
THEME_LIBRARY_FIX.md) - Consistent ISO strings - API Base URL Fix (this document) - Correct backend URL resolution
All three fixes were needed for the Theme Library to work properly!
Fixed: November 21, 2025 - 5:00 PM
Session: 11.25.1.1
Status: ✅ Complete and ready to test