mirror of
https://github.com/hanzoai/flow.git
synced 2026-10-17 01:29:18 +00:00
flowweb proxies /v1 and /v2 to the backend
The backend mounts its API at /v1 and /v2, but flowweb forwarded /api/, so every API call from the UI came back as the SPA shell. A routing test covers API paths, SPA routes and the method guard. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -22,10 +22,11 @@ var frontendFS embed.FS
|
||||
|
||||
// apiPrefixes go to the backend, never the SPA — an unmatched path here is the
|
||||
// backend's real JSON 404, never index.html (so a client never gets HTML where it
|
||||
// expects JSON). Everything else is a client-side route → the SPA shell.
|
||||
// expects JSON). The backend mounts its API at /v1 and /v2 (src/backend/base/flow/api/router.py).
|
||||
// Everything else is a client-side route → the SPA shell.
|
||||
var apiPrefixes = []string{
|
||||
"/api/", "/health", "/health_check", "/openapi.json", "/docs", "/redoc",
|
||||
"/.well-known/", "/logs", "/metrics",
|
||||
"/v1/", "/v2/", "/health", "/health_check", "/openapi.json", "/docs", "/redoc",
|
||||
"/.well-known/", "/logs",
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandlerRoutes(t *testing.T) {
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = io.WriteString(w, `{"path":"`+r.URL.Path+`"}`)
|
||||
}))
|
||||
defer backend.Close()
|
||||
|
||||
h, err := newHandler(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
method, path string
|
||||
backend bool
|
||||
status int
|
||||
}{
|
||||
{http.MethodGet, "/v1/version", true, http.StatusOK},
|
||||
{http.MethodPost, "/v1/login", true, http.StatusOK},
|
||||
{http.MethodGet, "/v1", true, http.StatusOK},
|
||||
{http.MethodGet, "/v2/files", true, http.StatusOK},
|
||||
{http.MethodGet, "/health_check", true, http.StatusOK},
|
||||
{http.MethodGet, "/logs-stream", true, http.StatusOK},
|
||||
{http.MethodGet, "/", false, http.StatusOK},
|
||||
{http.MethodGet, "/flows", false, http.StatusOK},
|
||||
{http.MethodGet, "/v10", false, http.StatusOK},
|
||||
{http.MethodPost, "/flows", false, http.StatusMethodNotAllowed},
|
||||
}
|
||||
for _, c := range cases {
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(c.method, c.path, nil))
|
||||
if rec.Code != c.status {
|
||||
t.Errorf("%s %s: status %d, want %d", c.method, c.path, rec.Code, c.status)
|
||||
continue
|
||||
}
|
||||
body := rec.Body.String()
|
||||
proxied := strings.Contains(body, `{"path":"`+c.path+`"}`)
|
||||
if proxied != c.backend {
|
||||
t.Errorf("%s %s: proxied=%v, want %v (body %.60q)", c.method, c.path, proxied, c.backend, body)
|
||||
}
|
||||
if !c.backend && c.status == http.StatusOK && !strings.Contains(body, "<html") {
|
||||
t.Errorf("%s %s: want the SPA shell, got %.60q", c.method, c.path, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user