package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "os" "strings" "time" ) func required(name string) string { value := os.Getenv(name); if value == "" { panic("Set " + name) }; return value } func getenv(name, fallback string) string { if value := os.Getenv(name); value != "" { return value }; return fallback } func postJSON(url string, payload any, token string, correlationId string) ([]byte, error) { body, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", url, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") if token != "" { req.Header.Set("Authorization", "Bearer "+token) } if correlationId != "" { req.Header.Set("X-Correlation-Id", correlationId) } return send(req) } func optional(name, fallback string) string { value := os.Getenv(name) if value == "" { return fallback } return value } func getJSON(url string, token string, correlationId string) ([]byte, error) { req, _ := http.NewRequest("GET", url, nil) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("X-Correlation-Id", correlationId) return send(req) } func send(req *http.Request) ([]byte, error) { client := &http.Client{Timeout: 45 * time.Second} resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() result, _ := io.ReadAll(resp.Body) if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(result)) } return result, nil } func values(fit, demand, margin, cost, risk, customer float64) map[string]float64 { return map[string]float64{ "assign_rental_vehicle_customer_fit_score": fit, "assign_rental_vehicle_vehicle_or_resource_fit": demand, "assign_rental_vehicle_operational_readiness": margin, "assign_rental_vehicle_financial_impact": cost, "assign_rental_vehicle_risk_exposure": risk, "assign_rental_vehicle_time_sensitivity": customer, } } func main() { identityURL := getenv("DECISIOQ_IDENTITY_URL", "https://identity.vinquery.com/connect/token") catalogURL := strings.TrimRight(getenv("DECISIOQ_DKS_URL", "https://dks.vinquery.com"), "/") decisionServiceURL := strings.TrimRight(getenv("DECISIOQ_DDE_URL", "https://dde.vinquery.com"), "/") correlationID := fmt.Sprintf("auto-rent-008-go-%d", time.Now().Unix()) tokenBody, err := postJSON(identityURL, map[string]string{ "clientId": required("DECISIOQ_CLIENT_ID"), "clientSecret": required("DECISIOQ_CLIENT_SECRET"), "audience": optional("DECISIOQ_AUDIENCE", "vinquery:api:decisioq"), }, "", "") if err != nil { panic(err) } var token struct{ JwtToken string `json:"jwtToken"` } json.Unmarshal(tokenBody, &token) if _, err = getJSON(catalogURL+"/decisioncatalog/decisions/AUTO-RENT-008", token.JwtToken, correlationID); err != nil { panic(err) } executionRequest := map[string]any{ "decisionId": "AUTO-RENT-008", "profileId": "balanced", "scenarioId": "standard_rental", "algorithm": "TOPSIS", "weightStrategy": "Expert", "runSensitivity": false, "requestContext": map[string]string{"correlationId": correlationID}, "options": []map[string]any{ {"optionId": "OPTION-001", "name": "Compact SUV Unit", "values": values(88, 91, 84, 76, 20, 26)}, {"optionId": "OPTION-002", "name": "Standard Sedan Unit", "values": values(79, 85, 92, 70, 18, 34)}, {"optionId": "OPTION-003", "name": "Premium SUV Unit", "values": values(92, 73, 68, 88, 42, 50)}, }, } result, err := postJSON(decisionServiceURL+"/api/v1/decide", executionRequest, token.JwtToken, correlationID) if err != nil { panic(err) } os.Stdout.Write(result) }