Skip to content

Commit

Permalink
minor enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
dipjyotimetia committed Mar 31, 2024
1 parent 93d259d commit bb7c050
Show file tree
Hide file tree
Showing 15 changed files with 229 additions and 52 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
test:
go test ./... -v --tags=integration

build:
docker compose up -d

clean:
docker compose down --rmi all --volumes

code-gen:
go generate ./...

schema-gen:
go run script/avsc2json/main.go schema/avro/expense.avsc > docker/schema/expense.json
3 changes: 2 additions & 1 deletion cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func main() {
cc := events.NewKafkaClient(cfg)
api := app.Group("/api")
router.ExpenseRouter(api, ctx, cc, cfg)
router.PaymentRouter(api, ctx, cc, cfg)
// Listen from a different goroutine
go func() {
if err := app.Listen(":8083"); err != nil {
Expand All @@ -55,7 +56,7 @@ func main() {
c := make(chan os.Signal, 1) // Create channel to signify a signal being sent
signal.Notify(c, os.Interrupt, syscall.SIGTERM) // When an interrupt or termination signal is sent, notify the channel

_ = <-c // This blocks the main thread until an interrupt is received
<-c // This blocks the main thread until an interrupt is received
log.Println("Gracefully shutting down...")
if err := app.Shutdown(); err != nil {
log.Printf("Error during shutdown: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ services:
- init-topic
environment:
BROKERS: kafka:9092
TOPICS: expense-topic
TOPICS: expense-topic,payment-topic,transaction-topic
SCHEMAREGISTRY: kafka:8081

kafka:
Expand Down
4 changes: 2 additions & 2 deletions docker/schema/expense.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"schema": "{ \"type\": \"record\", \"namespace\": \"com.expense\", \"name\": \"Expense\", \"fields\": [ { \"name\": \"expense_id\", \"type\": \"string\" }, { \"name\": \"user_id\", \"type\": \"string\" }, { \"name\": \"category\", \"type\": \"string\" }, { \"name\": \"amount\", \"type\": \"double\" }, { \"name\": \"currency\", \"type\": \"string\" }, { \"name\": \"timestamp\", \"type\": \"long\", \"logicalType\": \"timestamp-millis\" }, { \"name\": \"description\", \"type\": [\"null\", \"string\"], \"default\": null }, { \"name\": \"receipt\", \"type\": [\"null\", \"string\"], \"default\": null } ]}"
}
"schema": "{\"name\":\"com.expense.Expense\",\"type\":\"record\",\"fields\":[{\"name\":\"expense_id\",\"type\":\"string\"},{\"name\":\"user_id\",\"type\":\"string\"},{\"name\":\"category\",\"type\":\"string\"},{\"name\":\"amount\",\"type\":\"double\"},{\"name\":\"currency\",\"type\":\"string\"},{\"name\":\"timestamp\",\"type\":\"long\"},{\"name\":\"description\",\"type\":[\"null\",\"string\"]},{\"name\":\"receipt\",\"type\":[\"null\",\"string\"]}]}"
}
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ require (
)

require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -22,12 +22,12 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pierrec/lz4/v4 v4.1.19 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/stretchr/testify v1.7.5 // indirect
github.com/twmb/franz-go/pkg/kmsg v1.7.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/valyala/fasthttp v1.52.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/sys v0.18.0 // indirect
)
27 changes: 14 additions & 13 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA=
github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -10,8 +10,8 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hamba/avro/v2 v2.20.1 h1:3WByQiVn7wT7d27WQq6pvBRC00FVOrniP6u67FLA/2E=
github.com/hamba/avro/v2 v2.20.1/go.mod h1:xHiKXbISpb3Ovc809XdzWow+XGTn+Oyf/F9aZbTLAig=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand All @@ -32,12 +32,13 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pierrec/lz4/v4 v4.1.19 h1:tYLzDnjDXh9qIxSTKHwXwOYmm9d887Y7Y1ZkyXYHAN4=
github.com/pierrec/lz4/v4 v4.1.19/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
Expand All @@ -52,16 +53,16 @@ github.com/twmb/franz-go/pkg/sr v0.0.0-20240307025822-351e7fae879c h1:Qu83jF+b04
github.com/twmb/franz-go/pkg/sr v0.0.0-20240307025822-351e7fae879c/go.mod h1:egX+kicq83hpztv3PRCXKLNO132Ol9JTAJOCRZcqUxI=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0=
github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
8 changes: 4 additions & 4 deletions pkg/config/kafka.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (

// Config represents the application configuration.
type Config struct {
Brokers string `env:"BROKERS" envDefault:"localhost:9092"`
Topics string `env:"TOPICS" envDefault:"expense-topic"`
SchemaRegistry string `env:"SCHEMAREGISTRY" envDefault:"localhost:8081"`
Brokers string `env:"BROKERS" envDefault:"localhost:9092"`
Topics []string `env:"TOPICS" envDefault:"expense-topic,payment-topic,transaction-topic"`
SchemaRegistry string `env:"SCHEMAREGISTRY" envDefault:"localhost:8081"`
}

// KafkaTLS represents the configuration for Kafka TLS settings.
Expand All @@ -28,7 +28,7 @@ type KafkaTLS struct {
// NewConfig creates a new Config instance by parsing environment variables.
// It returns a pointer to the Config and an error if there was a problem parsing the environment variables.
func NewConfig() (*Config, error) {
var cfg Config
cfg := Config{}
if err := env.Parse(&cfg); err != nil {
return nil, fmt.Errorf("error processing environment variables: %w", err)
}
Expand Down
27 changes: 15 additions & 12 deletions pkg/events/Produce.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"context"
"fmt"

"github.com/dipjyotimetia/event-stream/gen"
"github.com/dipjyotimetia/event-stream/pkg/config"
"github.com/hamba/avro/v2"
"github.com/twmb/franz-go/pkg/kgo"
Expand All @@ -29,7 +28,6 @@ func NewKafkaClient(cfg *config.Config) *KafkaClient {
seeds := []string{cfg.Brokers}
client, err := kgo.NewClient(
kgo.SeedBrokers(seeds...),
kgo.DefaultProduceTopic("expense-topic"),
)
if err != nil {
fmt.Printf("error initializing Kafka producer client: %v\n", err)
Expand All @@ -53,30 +51,34 @@ func (c KafkaClient) Producer(ctx context.Context, record *kgo.Record) error {
}

// getSchema retrieves the Avro schema for the specified subject from the schema registry.
func getSchema(cfg config.Config, subject string) sr.SubjectSchema {
// getSchema retrieves the Avro schema for the specified subject from the schema registry.
func getSchema(cfg config.Config, subject string) (sr.SubjectSchema, error) {
rcl, err := sr.NewClient(sr.URLs(cfg.SchemaRegistry))
if err != nil {
_ = fmt.Errorf("unable to create schema registry client")
return sr.SubjectSchema{}, fmt.Errorf("unable to create schema registry client: %w", err)
}
schemaSubject, err := rcl.SchemaByVersion(context.Background(), subject, -1)
if err != nil {
_ = fmt.Errorf("unable to get schema registry client")
return sr.SubjectSchema{}, fmt.Errorf("unable to get schema registry client: %w", err)
}
return schemaSubject
return schemaSubject, nil
}

// SetExpenseRecord encodes the provided data using Avro and creates a Kafka record with the encoded value.
func (c KafkaClient) SetExpenseRecord(cfg *config.Config, ts interface{}) *kgo.Record {
schemaSubject := getSchema(*cfg, "expense-topic-value")
// SetRecord encodes the provided data using Avro and creates a Kafka record with the encoded value.
func (c KafkaClient) SetRecord(cfg *config.Config, ts interface{}, topic string, schemaType interface{}) (*kgo.Record, error) {
schemaSubject, err := getSchema(*cfg, topic+"-value")
if err != nil {
return nil, err
}
avroSchema, err := avro.Parse(schemaSubject.Schema.Schema)
if err != nil {
_ = fmt.Errorf("unable to parse avro schema")
return nil, fmt.Errorf("unable to parse avro schema: %w", err)
}

var serde sr.Serde
serde.Register(
schemaSubject.ID,
gen.Expense{},
schemaType,
sr.EncodeFn(func(v interface{}) ([]byte, error) {
return avro.Marshal(avroSchema, v)
}),
Expand All @@ -87,8 +89,9 @@ func (c KafkaClient) SetExpenseRecord(cfg *config.Config, ts interface{}) *kgo.R
tt := serde.MustEncode(ts)
record := kgo.Record{
Value: tt,
Topic: topic,
}
return &record
return &record, nil
}

// Ptr returns a pointer to the provided value.
Expand Down
16 changes: 6 additions & 10 deletions pkg/handler/expenseHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,7 @@ import (

// ExpenseHandler returns an HTTP handler function for creating expense records.
// It takes a KafkaClient instance and a Config instance as input.
// The handler function parses the JSON request body into an Expense struct,
// sets the Timestamp field to the current time if it's not already set,
// creates a Kafka record with the expense data, and sends it to the Kafka topic.
// Finally, it returns a success response.
func ExpenseHandler(ctx context.Context, client *events.KafkaClient, cfg *config.Config) fiber.Handler {
// Parse the JSON request body into an Expense struct
return func(c *fiber.Ctx) error {
var expense gen.Expense

Expand All @@ -34,15 +29,16 @@ func ExpenseHandler(ctx context.Context, client *events.KafkaClient, cfg *config
expense.Timestamp = time.Now().UnixNano() / int64(time.Millisecond)
}

// Create a Kafka record with the expense data
record := client.SetExpenseRecord(cfg, expense)
record, err := client.SetRecord(cfg, expense, "expense-topic", gen.Expense{})
if err != nil {
c.Status(http.StatusInternalServerError)
}

// Send the Kafka record to the Kafka topic
err := client.Producer(ctx, record)
err = client.Producer(ctx, record)
if err != nil {
c.Status(http.StatusInternalServerError)
}
// Return a success response

c.SendStatus(http.StatusOK) //nolint:errcheck
return c.Send([]byte("expense created successfully"))
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/handler/paymentHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package handler

import (
"context"
"net/http"
"time"

"github.com/dipjyotimetia/event-stream/gen"
"github.com/dipjyotimetia/event-stream/pkg/config"
"github.com/dipjyotimetia/event-stream/pkg/events"
"github.com/gofiber/fiber/v2"
)

func PaymentHandler(ctx context.Context, client *events.KafkaClient, cfg *config.Config) fiber.Handler {
return func(c *fiber.Ctx) error {
var payment gen.Payment

if err := c.BodyParser(&payment); err != nil {
c.Status(http.StatusBadRequest)
return err
}

// Set the Timestamp field to current time if it's not already set
if payment.Timestamp == 0 {
payment.Timestamp = time.Now().UnixNano() / int64(time.Millisecond)
}

record, err := client.SetRecord(cfg, payment, "payment-topic", gen.Payment{})
if err != nil {
c.Status(http.StatusInternalServerError)
}

err = client.Producer(ctx, record)
if err != nil {
c.Status(http.StatusInternalServerError)
}
c.SendStatus(http.StatusOK) //nolint:errcheck
return c.Send([]byte("expense created successfully"))
}
}
8 changes: 6 additions & 2 deletions pkg/router/expenseRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
)

// ExpenseRouter is the Router for GoFiber App
func ExpenseRouter(app fiber.Router,ctx context.Context, client *events.KafkaClient, cfg *config.Config) {
app.Post("/expense", handler.ExpenseHandler(ctx,client, cfg))
func ExpenseRouter(app fiber.Router, ctx context.Context, client *events.KafkaClient, cfg *config.Config) {
app.Post("/expense", handler.ExpenseHandler(ctx, client, cfg))
}

func PaymentRouter(app fiber.Router, ctx context.Context, client *events.KafkaClient, cfg *config.Config) {
app.Post("/payment", handler.PaymentHandler(ctx, client, cfg))
}
48 changes: 48 additions & 0 deletions script/avsc2json/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/hamba/avro/v2"
)

func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: avsc_to_json <input.avsc>")
return
}

avscFilename := os.Args[1]

avscBytes, err := os.ReadFile(avscFilename)
if err != nil {
fmt.Println("Error reading AVSC file:", err)
return
}

// Load the schema from a file or some other source
schema, err := avro.Parse(string(avscBytes))
if err != nil {
fmt.Println("Error parsing schema:", err)
return
}
output := map[string]interface{}{
"schema": schema.String(),
}

jsonBytes, err := json.MarshalIndent(output, "", " ")
if err != nil {
fmt.Println("Error marshalling to JSON:", err)
return
}
fmt.Println(string(jsonBytes))

// jsonFilename := strings.TrimSuffix(avscFilename, ".avsc") + ".json"
// err = os.WriteFile(jsonFilename, jsonBytes, 0644) //nolint:gosec
// if err != nil {
// fmt.Println("Error writing JSON file:", err)
// return
// }
}
18 changes: 18 additions & 0 deletions script/avsc2json/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# AVSC to JSON Converter
This script is a simple utility written in Go that converts Avro schema files (.avsc) to JSON format.

### Usage
To use this script, you need to pass the .avsc file as a command-line argument:

Replace <input.avsc> with the path to your Avro schema file.

### How It Works
The script reads the Avro schema file specified as a command-line argument. It then converts the schema to JSON format and writes the output to a new file with the same name as the input file but with a .json extension.

For example, if you run go run main.go example.avsc, the script will create a new file named example.json with the JSON representation of the Avro schema.

### Error Handling
If the script encounters an error while reading the Avro schema file or converting it to JSON, it will print an error message and exit.

### Contributing
Contributions are welcome. Please submit a pull request if you have any improvements or bug fixes.
2 changes: 1 addition & 1 deletion tests/expense_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//go:build integration
// +build integration

package main
package tests

import (
"bytes"
Expand Down
Loading

0 comments on commit bb7c050

Please sign in to comment.