package stdlib import ( "context" "fmt" "io" "maps" "net/http" "strings" "reichard.io/poiesis/internal/functions" ) func init() { functions.RegisterAsyncFunction("fetch", Fetch) } type FetchArgs struct { Input string `json:"input"` Init *RequestInit `json:"init,omitempty"` } func (f FetchArgs) Validate() error { return nil } type RequestInit struct { Method string `json:"method,omitempty"` Headers map[string]string `json:"headers,omitempty"` Body *string `json:"body,omitempty"` } func (o *RequestInit) Validate() error { if o.Method == "" { o.Method = "GET" } return nil } type Response struct { OK bool `json:"ok"` Status int `json:"status"` Body string `json:"body"` Headers map[string]string `json:"headers"` } type AddArgs struct { A int `json:"a"` B int `json:"b"` } func (a AddArgs) Validate() error { return nil } type GreetArgs struct { Name string `json:"name"` } func (g GreetArgs) Validate() error { return nil } func Fetch(_ context.Context, args FetchArgs) (Response, error) { method := "GET" headers := make(map[string]string) if args.Init != nil { method = args.Init.Method if args.Init.Headers != nil { maps.Copy(headers, args.Init.Headers) } } req, err := http.NewRequest(method, args.Input, nil) if err != nil { return Response{}, fmt.Errorf("failed to create request: %w", err) } for k, v := range headers { req.Header.Set(k, v) } resp, err := http.DefaultClient.Do(req) if err != nil { return Response{}, fmt.Errorf("failed to fetch: %w", err) } defer func() { _ = resp.Body.Close() }() body, err := io.ReadAll(resp.Body) if err != nil { return Response{}, fmt.Errorf("failed to read body: %w", err) } resultHeaders := make(map[string]string) for key, values := range resp.Header { if len(values) > 0 { val := values[0] resultHeaders[key] = val resultHeaders[strings.ToLower(key)] = val } } return Response{ OK: resp.StatusCode >= 200 && resp.StatusCode < 300, Status: resp.StatusCode, Body: string(body), Headers: resultHeaders, }, nil }