mehdihadeli / Go-MediatR

🚃 A library for handling mediator patterns and simplified CQRS patterns within an event-driven architecture. inspired by csharp MediatR library.
https://pkg.go.dev/github.com/mehdihadeli/go-mediatr
MIT License
194 stars 16 forks source link

[Help] Go-MediatR with Fx #13

Open tomflenner opened 8 months ago

tomflenner commented 8 months ago

Hi,

Do you have any examples of Go-MediatR integration with uber-fx? 👀

I tried something like that, but I'm not sure if it's the best way (it's a quick fork of your example) :

package core

import (
    "context"
    "log"

    dtos "example.com/fxdemo/core/dtos"
    interfaces "example.com/fxdemo/core/interfaces"
    mappers "example.com/fxdemo/core/mappers"
    "github.com/mehdihadeli/go-mediatr"
    "go.uber.org/fx"
)

// Command Handler
type CreateProductCommandHandler struct {
    productRepository interfaces.ProductRepository
}

func NewCreateProductCommandHandler(productRepository interfaces.ProductRepository) *CreateProductCommandHandler {
    return &CreateProductCommandHandler{productRepository: productRepository}
}

func (c *CreateProductCommandHandler) Handle(ctx context.Context, command *CreateProductCommand) (*CreateProductCommandResponse, error) {
    productDto := &dtos.ProductDto{
        Name:        command.Name,
        Description: command.Description,
        Price:       command.Price,
    }

    product := mappers.MapProductDtoToProduct(productDto)

    createdProduct, err := c.productRepository.AddProduct(product)

    if err != nil {
        return nil, err
    }

    response := &CreateProductCommandResponse{ProductUUID: createdProduct.ProductUUID}

    return response, nil
}

func registerHandler(createCommandHandler *CreateProductCommandHandler) {
    err := mediatr.RegisterRequestHandler[*CreateProductCommand, *CreateProductCommandResponse](createCommandHandler)
    if err != nil {
        log.Fatal(err)
    }
}

var CreateProductModule = fx.Options(
    fx.Provide(NewCreateProductCommandHandler),
    fx.Invoke(registerHandler))

with a main fx.go for my layer :

package core

import (
    core "example.com/fxdemo/core/commands/product/create"
    "go.uber.org/fx"
)

var Module = fx.Options(
    core.CreateProductModule,
)

To be able to use like this in my endpoint :

package api

import (
    "fmt"

    handler "example.com/fxdemo/api/handler"
    core "example.com/fxdemo/core/commands/product/create"
    "github.com/gin-gonic/gin"
    "github.com/mehdihadeli/go-mediatr"
    "go.uber.org/fx"
)

func registerProductRoutes(handler *handler.Handler) {
    v1 := handler.Gin.Group("/api/v1")
    {
        product := v1.Group("product")
        {
            product.POST("", func(c *gin.Context) {
                command := core.NewCreateProductCommand("Product test", "Description test", 10)

                result, err := mediatr.Send[*core.CreateProductCommand, *core.CreateProductCommandResponse](c, command)

                if err != nil {
                    message := fmt.Errorf(err.Error())
                    fmt.Println(message)
                }

                fmt.Println(result)

                c.JSON(200, gin.H{"message": "Post PRODUCT OK"})
            })
        }
    }
}

var ProductControllerModule = fx.Options(fx.Invoke(registerProductRoutes))

Thansk in advance ! 🙏🏻

Feel free to give any feedback on my code 👍🏻

github-actions[bot] commented 8 months ago

Welcome to go-mediatr. Thank you for reporting your first issue. Please check out our contributor guide.

mehdihadeli commented 8 months ago

Yes, it is fine and clean in my opinion. You are feel free for adding it also to the examples folder, for guiding other developers to use fx