Skip to content

Commit 8306ab9

Browse files
fix: ensure Fetch API tags field is always an array, never null
- Add TagsOrEmpty in pkg/grpc/common.go for proto/cloudevent conversion - Normalize tags in eventrepo (toCloudEvent, ListCloudEventsFromIndexes) - Normalize tags in indexToModel for latestIndex/indexes GraphQL responses - Schema: tags type [String!]! so API contract guarantees non-null array - Regenerate gqlgen Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent d79878d commit 8306ab9

5 files changed

Lines changed: 53 additions & 43 deletions

File tree

internal/graph/convert.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ func resolveLimit(limit *int) int {
5656
// indexToModel converts a CloudEvent index entry to the GraphQL model,
5757
// using the CloudEventHeader from the library directly.
5858
func indexToModel(idx cloudevent.CloudEvent[eventrepo.ObjectInfo]) *model.CloudEventIndex {
59+
idx.CloudEventHeader.Tags = grpc.TagsOrEmpty(idx.CloudEventHeader.Tags)
5960
return &model.CloudEventIndex{
6061
Header: &idx.CloudEventHeader,
6162
IndexKey: idx.Data.Key,

internal/graph/generated.go

Lines changed: 36 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/eventrepo/eventrepo.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ func (s *Service) ListCloudEventsFromIndexes(ctx context.Context, indexes []clou
190190
for i := range indexes {
191191
// Some objects have multiple cloud events so we cache the objects to avoid fetching them multiple times.
192192
if data, ok := objectsByKeys[indexes[i].Data.Key]; ok {
193-
events[i] = cloudevent.RawEvent{CloudEventHeader: indexes[i].CloudEventHeader, Data: data}
193+
hdr := indexes[i].CloudEventHeader
194+
hdr.Tags = grpc.TagsOrEmpty(hdr.Tags)
195+
events[i] = cloudevent.RawEvent{CloudEventHeader: hdr, Data: data}
194196
continue
195197
}
196198
events[i], err = s.GetCloudEventFromIndex(ctx, indexes[i], bucketName)
@@ -315,6 +317,7 @@ func toCloudEvent(dbHdr *cloudevent.CloudEventHeader, data []byte) (cloudevent.R
315317
ev.Data = nil // never expose decoded bytes in Data
316318
}
317319
ev.CloudEventHeader = *dbHdr
320+
ev.CloudEventHeader.Tags = grpc.TagsOrEmpty(ev.CloudEventHeader.Tags)
318321
return ev, nil
319322
}
320323

pkg/grpc/common.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import (
77
"google.golang.org/protobuf/types/known/timestamppb"
88
)
99

10+
// TagsOrEmpty returns the slice if non-nil and non-empty, otherwise a non-nil empty slice.
11+
// Ensures API always returns an array for tags, never null.
12+
func TagsOrEmpty(tags []string) []string {
13+
if len(tags) > 0 {
14+
return tags
15+
}
16+
return []string{}
17+
}
18+
1019
// AsRawCloudEvent converts the CloudEvent to a cloudevent.RawEvent.
1120
func (c *CloudEvent) AsRawCloudEvent() cloudevent.RawEvent {
1221
return cloudevent.RawEvent{
@@ -41,7 +50,7 @@ func (c *CloudEventHeader) AsCloudEventHeader() cloudevent.CloudEventHeader {
4150
DataVersion: c.GetDataVersion(),
4251
Extras: extras,
4352
Signature: c.GetSignature(),
44-
Tags: c.GetTags(),
53+
Tags: TagsOrEmpty(c.GetTags()),
4554
}
4655
}
4756

@@ -72,7 +81,7 @@ func CloudEventHeaderToProto(event *cloudevent.CloudEventHeader) *CloudEventHead
7281
DataVersion: event.DataVersion,
7382
Extras: extras,
7483
Signature: event.Signature,
75-
Tags: event.Tags,
84+
Tags: TagsOrEmpty(event.Tags),
7685
}
7786
}
7887

schema/base.graphqls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ type CloudEventHeader {
6060
dataschema: String
6161
dataversion: String
6262
signature: String
63-
tags: [String!]
63+
tags: [String!]!
6464
}
6565

6666
"""

0 commit comments

Comments
 (0)