Files
poimen-workflows/internal/api/server.go
T
2026-09-05 06:00:58 -07:00

118 lines
3.5 KiB
Go

package api
import (
"fmt"
"log"
"net/http"
"strings"
"go.temporal.io/sdk/client"
"github.com/rockliang/poimen/workflows/pkg/db"
)
// Server handles HTTP routing for workflow APIs
type Server struct {
api *WorkflowAPI
logger *log.Logger
}
// NewServer creates new HTTP server with database connection
func NewServer(database *db.DB, temporalClient client.Client, logger *log.Logger) *Server {
return &Server{
api: NewWorkflowAPI(database, temporalClient, logger),
logger: logger,
}
}
// ServeHTTP dispatches HTTP requests to appropriate handler
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Enable CORS
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
}
path := r.URL.Path
method := r.Method
s.logger.Printf("%s %s", method, path)
// Route requests
switch {
// Workflow endpoints
case path == "/workflows" && method == http.MethodPost:
s.api.CreateWorkflow(w, r)
case path == "/workflows" && method == http.MethodGet:
s.api.ListWorkflows(w, r)
case strings.HasPrefix(path, "/workflows/") && method == http.MethodGet:
id := strings.TrimPrefix(path, "/workflows/")
// Exclude special paths
if !strings.Contains(id, "/") {
s.api.GetWorkflow(w, r, id)
} else if strings.HasSuffix(id, "/executions") {
// GET /workflows/{id}/executions
workflowID := strings.TrimSuffix(id, "/executions")
s.api.ListExecutions(w, r, workflowID)
}
case strings.HasPrefix(path, "/workflows/") && method == http.MethodPut:
id := extractID(path, "/workflows/")
s.api.UpdateWorkflow(w, r, id)
case strings.HasPrefix(path, "/workflows/") && method == http.MethodDelete:
id := extractID(path, "/workflows/")
s.api.DeleteWorkflow(w, r, id)
// Execute workflow
case strings.HasSuffix(path, "/execute") && method == http.MethodPost:
// POST /workflows/{id}/execute
parts := strings.Split(path, "/")
if len(parts) >= 4 && parts[1] == "workflows" && parts[3] == "execute" {
s.api.ExecuteWorkflow(w, r, parts[2])
}
// GraphRAG query endpoint
case strings.HasSuffix(path, "/query") && method == http.MethodPost:
// POST /workflows/{id}/query
parts := strings.Split(path, "/")
if len(parts) >= 4 && parts[1] == "workflows" && parts[3] == "query" {
s.api.QueryWorkflowGraph(w, r, parts[2])
}
// Relation versions endpoint
case strings.Contains(path, "/relations/") && strings.Contains(path, "/versions") && method == http.MethodGet:
// GET /workflows/{id}/relations/{edge_id}/versions
parts := strings.Split(path, "/")
if len(parts) >= 6 && parts[1] == "workflows" && parts[3] == "relations" && parts[5] == "versions" {
s.api.GetWorkflowRelationVersions(w, r, parts[2], parts[4])
}
// Execution endpoints
case strings.HasPrefix(path, "/executions/") && method == http.MethodGet:
id := extractID(path, "/executions/")
s.api.GetExecution(w, r, id)
default:
http.Error(w, "Not found", http.StatusNotFound)
}
}
// extractID extracts resource ID from path
func extractID(path, prefix string) string {
id := strings.TrimPrefix(path, prefix)
if idx := strings.Index(id, "/"); idx != -1 {
return id[:idx]
}
return id
}
// Start starts the HTTP server
func (s *Server) Start(port int) error {
addr := fmt.Sprintf(":%d", port)
s.logger.Printf("Starting API server on %s", addr)
return http.ListenAndServe(addr, s)
}