Tuesday, July 2, 2024
HomeGolangAssist with clear structure for internet utility - Technical Dialogue

Assist with clear structure for internet utility – Technical Dialogue


Howdy,

I’ve learn a whole lot of articles (often to easy to reply to what I’m questioning), learn some books, pratice lots however I’ve nonetheless questions on learn how to structure an internet utility or a minimum of, for a fancy utility, I’m discovering myself writing capabilities that do an excessive amount of issues and I’m not capable of refactor in a great way.

For my internet utility, I’m at all times utilizing:

  • sqlc to generate the SQL boilerplate code
  • chi router or various
  • templ to construct HTML with Go

So right here is my undertaking structure (approximatively):

cmd/   # predominant app right here
inside/
    database/               # code to initialise database, create connections...
       db/migrations/*sql   # sql code migrations (for dbmate or alternate options)
    html
        handlers/           # all my handlers
        views/              # all of the templ code to generate html
    middlewares/
    repository/             # code generated by sqlc
    ...
pkg/
    config                  # config bundle to deal with the configuration of the app
    consumer                    # to deal with customers for examples
    token                   # to deal with the auth of customers for instance
    subscription            # to deal with the subscriptions of consumer
    ...
queries/                    # incorporates all requests that shall be utilized by sqlc to generate the boilerplate code

Packages consumer, token, subscription handles usually the fundamental operations (create, fetch, delete, replace). I’m writing all of them in the identical approach, it’s a service layer.

For instance, for my consumer bundle, I’ve this:

bundle consumer
...

kind Service struct {
	queries *repository.Queries
}

func NewService(db repository.DBTX) *Service {
	queries := repository.New(db)
	return &Service{
		queries: queries,
	}
}

func (s *Service) CreateNewUser(...)

// GetUserFromEmail returns the consumer with the given e mail
func (s *Service) GetUserFromEmail(ctx context.Context, e mail string) (repository.ClientsUser, error) {
	return s.queries.GetUserWithItsEmail(ctx, e mail)
}

...

Now for my handlers bundle, as they should use all of the providers, the constructor will be big. In my precise undertaking, it’s one thing like this:

bundle handlers

func NewController(cfg config.ConfigApp, userSvc *consumer.Service,
	tokenSvc *token.Service, fileSvc *file.Service,
	countrySvc *nation.Service, redisClient *redis.Shopper,
	retailer storage.Storage, tSvc *turnstile.TurnstileSvc,
	mailSvc mailservice.SendMailer,
	stripeSvc *stripesvc.StripeSvc,
	subscriptionSvc *subscription.Service,
	productSvc *product.Service) *Controller {
	return &Controller{
		cfg:             cfg,
		userSvc:         userSvc,
		tokenSvc:        tokenSvc,
		fileSvc:         fileSvc,
		countrySvc:      countrySvc,
		storage:         retailer,
		turnstileSvc:    tSvc,
		mailSvc:         mailSvc,
		stripeSvc:       stripeSvc,
		subscriptionSvc: subscriptionSvc,
		productSvc:      productSvc,
	}
}

...

Does it appear okay to have a such controller ? (It’s very anoying to jot down unit checks with that, even when I can go nil typically)

And now’s my predominant downside. I’ve enterprise logic in my handler. For instance, for a webapp that enable customers to add information. The enterprise logic might be totally different if the consumer has a subscription or not, and be totally different in perform of the kind of the subscription.

I discover myself writing the add handler like that:

  • examine JWT token is legitimate with tokensvc ( this half needs to be in a middleware, happy with that)
  • determine consumer from the e-mail within the token with usersvc
  • retrieve the dimensions of the request to examine later if the subscription of the consumer enable to add it
  • get the lively product for the consumer
  • calculating the uploaded information to examine if the consumer can add the precise file
  • I’ve some enterprise logic primarily based on subscriptions
  • and right here I deal with the add of the file

This handler use:

  • token service
  • subscription service
  • product service
  • consumer service

I’m questioning if the consumer service mustn’t use itself subscriptions service, product service for instance ? My predominant enterprise logic is round that.

Should you had the endurance to learn till right here, thanks.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments