How the WebUI Admin Console Interacts with the Go Backend in DS2API
The DS2API WebUI admin console communicates with the Go backend via REST endpoints under the /admin prefix, using a Vite development proxy in local development and static file serving with API route registration in production.
The DS2API repository provides a modern React-based administrative interface that seamlessly integrates with its Go server infrastructure. This architecture separates the frontend presentation layer from backend business logic through a clearly defined HTTP JSON interface. Understanding how the WebUI admin console interacts with the Go backend requires examining both the development proxy configuration and the production static file serving mechanism.
Architecture Overview
The interaction follows a layered pattern with distinct responsibilities. The frontend handles UI components and state management through a thin apiFetch wrapper located in files like webui/src/features/settings/settingsApi.js. During development, a Vite proxy forwards requests from port 5173 to the Go server on port 5001. In production, the Go server serves pre-built static files from static/admin while simultaneously registering the same API routes. The backend handlers in internal/httpapi/admin/* implement the actual business logic for configuration, accounts, and proxy management.
Development Request Flow
During development, the Vite dev server runs on http://localhost:5173 while the Go backend listens on port 5001. When the admin UI makes a request to /admin/settings, Vite's proxy configuration intercepts the call and forwards it to the backend.
The proxy configuration in webui/vite.config.js distinguishes between API calls and page navigation requests:
// webui/vite.config.js – proxy definition
proxy: {
'/admin': {
target: 'http://localhost:5001',
changeOrigin: true,
// page navigation → let Vite serve index.html
bypass(req) {
const url = req.url
if (url === '/admin' || url === '/admin/' || url === '/admin?') {
console.log('[Vite Proxy] Bypass (page):', url)
return '/index.html'
}
console.log('[Vite Proxy] Proxy to backend:', url)
},
},
// … other proxies (e.g., /v1 for the public API)
},
This configuration ensures that API requests reach the Go server while the single-page application (SPA) routes are handled by Vite's dev server. The Go server receives the request through the router mounted in internal/server/router.go.
Production Static Serving
In production, the React application is built using npm run build, which outputs static assets to the static/admin directory. The Go binary embeds a handler in internal/webui/handler.go that serves these files directly and implements SPA fallback behavior.
// internal/webui/handler.go – serving built SPA
func (h *Handler) admin(w http.ResponseWriter, r *http.Request) {
staticDir := resolveStaticAdminDir(h.StaticDir)
if fi, err := os.Stat(staticDir); err == nil && fi.IsDir() {
h.serveFromDisk(w, r, staticDir) // serve JS/CSS or index.html
return
}
http.Error(w, "WebUI not built. Run `cd webui && npm run build` first.", http.StatusNotFound)
}
If the request path does not resolve to a static asset (such as /admin/settings), the handler falls back to serving index.html only for page routes (/admin or /admin/). API calls continue to match registered routes handled by the dedicated admin handlers.
Backend Route Registration
The Go server registers all admin endpoints in internal/server/router.go using Chi router middleware. This registration occurs regardless of environment, ensuring consistent API behavior.
// internal/server/router.go – mounting admin routes
r.Route("/admin", func(ar chi.Router) {
admin.RegisterRoutes(ar, adminHandler) // all admin handlers
})
The router also includes a fallback mechanism for unknown admin paths that delegates to the WebUI handler for SPA routing:
r.NotFound(func(w http.ResponseWriter, req *http.Request) {
if strings.HasPrefix(req.URL.Path, "/admin/") && webuiHandler.HandleAdminFallback(w, req) {
return
}
http.NotFound(w, req)
})
Frontend API Communication
All React components interact with the backend through a centralized apiFetch utility that automatically prefixes /admin to requests and handles JSON serialization. The webui/src/features/settings/settingsApi.js file demonstrates this pattern for CRUD operations:
// webui/src/features/settings/settingsApi.js
export async function fetchSettings(apiFetch, t) {
const res = await apiFetch('/admin/settings')
return { res, data: await res.json() }
}
export async function putSettings(apiFetch, payload) {
const res = await apiFetch('/admin/settings', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
})
return { res, data: await res.json() }
}
Components consume these helpers through React hooks, ensuring the UI never directly accesses Go structs but instead relies on the HTTP JSON contract. Authentication logic follows the same pattern, with webui/src/app/useAdminAuth.js handling JWT tokens via /admin/login and /admin/verify endpoints.
Summary
- Development proxy: Vite forwards
/admin/*requests from port 5173 to the Go backend on port 5001, while serving the SPA directly - Production serving: The Go binary serves built static files from
static/adminwith automatic fallbacks toindex.htmlfor client-side routes - API routing: All admin endpoints are registered under
/adminininternal/server/router.gousing Chi router middleware - Frontend abstraction: The React UI uses a shared
apiFetchwrapper located inwebui/src/features/settings/settingsApi.jsto communicate through JSON HTTP contracts - Source locations: Business logic resides in
internal/httpapi/admin/*, static serving ininternal/webui/handler.go, and proxy configuration inwebui/vite.config.js
Frequently Asked Questions
What port does the DS2API Go backend use during development?
The Go backend listens on port 5001 during development. The Vite dev server running on port 5173 proxies all /admin/* API requests to this port, allowing the React frontend to communicate with the backend as if they were the same origin.
How does DS2API handle client-side routing in production?
When a request to /admin/settings or similar routes arrives in production, the internal/webui/handler.go first attempts to serve a matching static file. If no file exists, it falls back to serving index.html for page routes, allowing the React Router to handle the navigation. API routes are intercepted by the registered handlers before this fallback occurs.
Where are the admin API business logic handlers located?
All admin-specific business logic is implemented in the internal/httpapi/admin/* package. This includes handlers for settings, accounts, proxy configuration, and authentication. These handlers are registered in internal/server/router.go under the /admin route prefix.
What happens if the WebUI static files are not built before running the Go server?
If the static/admin directory does not exist, the admin handler in internal/webui/handler.go returns an HTTP 404 error with the message: "WebUI not built. Run cd webui && npm run build first." This prevents deployment of a broken admin interface and provides clear instructions for resolving the issue.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →