diff --git a/v2/protocol/http/utility.go b/v2/protocol/http/utility.go index 056ebe677..c1f16a7dd 100644 --- a/v2/protocol/http/utility.go +++ b/v2/protocol/http/utility.go @@ -6,7 +6,9 @@ package http import ( + "bytes" "context" + "encoding/json" nethttp "net/http" "github.com/cloudevents/sdk-go/v2/binding" @@ -36,3 +38,27 @@ func NewEventsFromHTTPResponse(resp *nethttp.Response) ([]event.Event, error) { msg := NewMessageFromHttpResponse(resp) return binding.ToEvents(context.Background(), msg, msg.BodyReader) } + +// NewHTTPRequestFromEvents creates a http.Request object that can be used with any http.Client. +func NewHTTPRequestFromEvents(ctx context.Context, url string, events []event.Event) (*nethttp.Request, error) { + // Sending batch events is quite straightforward, as there is only JSON format, so a simple implementation. + for _, e := range events { + if err := e.Validate(); err != nil { + return nil, err + } + } + var buffer bytes.Buffer + err := json.NewEncoder(&buffer).Encode(events) + if err != nil { + return nil, err + } + + request, err := nethttp.NewRequestWithContext(ctx, nethttp.MethodPost, url, &buffer) + if err != nil { + return nil, err + } + + request.Header.Set(ContentType, event.ApplicationCloudEventsBatchJSON) + + return request, nil +} diff --git a/v2/protocol/http/utility_test.go b/v2/protocol/http/utility_test.go index 3869ceafd..131f517b2 100644 --- a/v2/protocol/http/utility_test.go +++ b/v2/protocol/http/utility_test.go @@ -14,11 +14,11 @@ import ( "net/http/httptest" "testing" - "github.com/stretchr/testify/require" - "github.com/cloudevents/sdk-go/v2/binding" "github.com/cloudevents/sdk-go/v2/event" "github.com/cloudevents/sdk-go/v2/test" + "github.com/google/uuid" + "github.com/stretchr/testify/require" ) func TestNewEventFromHttpRequest(t *testing.T) { @@ -115,3 +115,42 @@ func TestNewEventsFromHTTPResponse(t *testing.T) { require.Len(t, events, 1) test.AssertEvent(t, events[0], test.IsValid()) } + +func TestNewHTTPRequestFromEvents(t *testing.T) { + var events []event.Event + e := event.New() + e.SetID(uuid.New().String()) + e.SetSource("example/uri") + e.SetType("example.type") + require.NoError(t, e.SetData(event.ApplicationJSON, map[string]string{"hello": "world"})) + events = append(events, e.Clone()) + + e.SetID(uuid.New().String()) + require.NoError(t, e.SetData(event.ApplicationJSON, map[string]string{"goodbye": "world"})) + events = append(events, e) + + require.Len(t, events, 2) + require.NotEqual(t, events[0], events[1]) + + // echo back what we get, so we can compare events at either side. + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set(ContentType, r.Header.Get(ContentType)) + b, err := io.ReadAll(r.Body) + require.NoError(t, err) + require.NoError(t, r.Body.Close()) + _, err = w.Write(b) + require.NoError(t, err) + })) + defer ts.Close() + + req, err := NewHTTPRequestFromEvents(context.Background(), ts.URL, events) + require.NoError(t, err) + + resp, err := ts.Client().Do(req) + require.NoError(t, err) + + result, err := NewEventsFromHTTPResponse(resp) + require.NoError(t, err) + + require.Equal(t, events, result) +}