Skip to content

strider2038/digen

Repository files navigation

DIGEN - Dependency Injection Container Generator

Installation

Install on Linux

# binary will be $(go env GOPATH)/bin/digen
sh -c "$(curl --location https://raw.githubusercontent.com/strider2038/digen/master/install.sh)" -- -d -b $(go env GOPATH)/bin
digen version

Go installer

go install github.com/strider2038/digen/cmd/digen@latest
digen version

How to use

Initialize a new container

To initialize new container skeleton run command.

digen init

Then describe your service definitions in the Container struct (<workdir>/internal/definitions/container.go). See examples. After any update run digen generate command to generate container and factories.

File structure

  • base directory (recommended name di)
    • container.go - generated public container
    • internal - directory with internal packages
      • container.go - generated internal di container
      • definitions - package with container and service definitions (configuration file)
        • container.go - structs describing di containers (describe here your services)
      • lookup - directory with lookup container contracts
        • container.go - generated interfaces for internal di container (to use in factories package)
      • factories - package with manually written factory functions to build up services

Service definition options

To set up service definition use tags:

  • tag di for quick options;
  • tag factory_name to set up factory filename (without extension);
  • tag public_name to override service getter for public container.

To set up quick options use tag di with combination of values:

  • set - to generate setters for internal and public containers;
  • close - to generate closer method call;
  • required - to generate argument for public container constructor;
  • public - to generate getter for public container;
  • external - no definition, panic if empty, force public setter.

Example of definitions/container.go

type Container struct {
    Configuration config.Configuration `di:"required"`
    Logger        *log.Logger          `di:"required"`
    Conn          *sql.Conn            `di:"external,close"`

    Handler *httpadapter.GetEntityHandler `di:"public"`

    UseCases     UseCaseContainer
    Repositories RepositoryContainer
}

type UseCaseContainer struct {
    FindEntity *usecase.FindEntity
}

type RepositoryContainer struct {
    EntityRepository domain.EntityRepository `di:"set"`
}

Known issues

Struct field is compared with nil for internal container

Workaround: don't use struct by values as services or set required option to generate constructor.

TODO

  • public container generator
  • use cobra/viper
  • SetError method
  • generate package docs
  • skeleton generation command (init)
  • import definitions package
  • remove unnecessary imports
  • definitions generator
  • handle multiple containers
  • better console output via logger
  • definitions for multiple containers
  • unique names for separate container definitions
  • prompt for init (set work_dir, write first config)
  • better generation with _config.go file
  • apply gofmt
  • move contracts into separate package
  • generate README.md for root package
  • ability to choose specific file for factory func
  • ability to set public definition name
  • check app version in config
  • force variable name / package name uniqueness
  • custom close functions
  • describe basic app example
  • add complex app example with tests and fake repository
  • multi container config
  • parse from multiple definition files (may encounter potential conflicts for imports)
  • definitions updater
  • write doc