Since I'm learning the Google Pub/Sub library I've set up a local instance of the Pub/Sub and created 2 apps: 1 to send a message and one to receive it. So far so good,I've managed to set up the subscriptions and topics and I receive the messages, but there's an issue that I noticed. I tried to send a message with nested struct fields but I don't reveive them. This is my code:
Sender:
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"cloud.google.com/go/pubsub"
"github.com/joho/godotenv"
)
type Payload struct {
ID string
Type string
Name string
Image
Thumbnail
}
type Image struct {
URL string
Width string
Height string
}
type Thumbnail struct {
URL string
Width string
Height string
}
func main() {
godotenv.Load(".env")
w := os.Stdout
projectID := os.Getenv("PROJECT_ID")
topicID := os.Getenv("TOPIC_ID")
message := Payload{
ID: "1",
Type: "image",
Name: "Image 1",
Image: Image{
URL: "https://example.com/image1",
Width: "100",
Height: "100",
},
Thumbnail: Thumbnail{
URL: "https://example.com/image1/thumb",
Width: "50",
Height: "50",
},
}
if err := publish(w, projectID, topicID, message); err != nil {
fmt.Fprintf(w, "Failed to publish: %v", err)
}
}
func publish(w io.Writer, projectID, topicID string, msg Payload) error {
ctx := context.Background()
client, err := pubsub.NewClient(ctx, projectID)
if err != nil {
return fmt.Errorf("create new client: %w", err)
}
defer client.Close()
t := client.Topic(topicID)
payload, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("marshal payload: %w", err)
}
result := t.Publish(ctx, &pubsub.Message{
Data: payload,
})
id, err := result.Get(ctx)
if err != nil {
return fmt.Errorf("pubsub: result.Get: %w", err)
}
fmt.Fprintf(w, "Published a message; msg ID: %v\n", id)
return nil
}
Receiver:
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"log"
"os"
"cloud.google.com/go/pubsub"
)
type Payload struct {
ID string
Type string
Name string
Image
Thumbnail
}
type Image struct {
URL string
Width string
Height string
}
type Thumbnail struct {
URL string
Width string
Height string
}
func main() {
projectID := os.Getenv("PROJECT_ID")
subscriptionID := os.Getenv("SUBSCRIPTION_ID")
if err := readMessages(projectID, subscriptionID); err != nil {
fmt.Printf("read message: %v", err)
}
}
func readMessages(projectID, subscriptionID string) error {
ctx := context.Background()
client, err := pubsub.NewClient(ctx, projectID)
if err != nil {
return fmt.Errorf("create new client: %w", err)
}
defer client.Close()
sub := client.Subscription(subscriptionID)
err = sub.Receive(context.Background(), func(ctx context.Context, m *pubsub.Message) {
result := Payload{}
message := m.Data
if err := json.Unmarshal(message, &result); err != nil {
log.Printf("unmarshal message: %v", err)
m.Nack()
return
}
log.Printf("get message: %s", m.Data)
m.Ack()
})
if err != nil && !errors.Is(err, context.Canceled) {
return fmt.Errorf("receive message: %w", err)
}
return nil
}
Result from the receiver is: Got message: {"ID":"1","Type":"image","Name":"Image 1"}
My question is why am I not receiving the nested fields?
Found the issue. The JSON tags were missing on the structs. Now the struct looks like this:
type Payload struct {
ID string `json:"ID"`
Type string `json:"Type"`
Name string `json:"Name"`
Image Image `json:"Image"`
Thumbnail Thumbnail `json:"Thumbnail"`
}
type Image struct {
URL string `json:"URL"`
Width string `json:"Width"`
Height string `json:"Height"`
}
type Thumbnail struct {
URL string `json:"URL"`
Width string `json:"Width"`
Height string `json:"Height"`
}
And the result looks like this:
Got message: {"ID":"1","Type":"image","Name":"Image 1","Image":{"URL":"https://example.com/image1","Width":"100","Height":"100"},"Thumbnail":{"URL":"https://example.com/image1/thumb","Width":"50","Height":"50"}}