di

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2025 License: MIT Imports: 11 Imported by: 0

README

Dependency Injection

Overview

The Dependency Injection (DI) component provides a flexible and type-safe dependency injection container for Go applications. It helps manage application dependencies, promotes loose coupling, and simplifies testing by providing a centralized way to create and access services.

Features

  • Generic Containers: Type-safe dependency injection using Go generics
  • Layered Architecture Support: Built-in support for repositories, domain services, and application services
  • Configuration Management: Integrated configuration handling
  • Validation: Built-in validation using go-playground/validator
  • Logging Integration: Seamless integration with the logging component
  • Resource Management: Automatic resource cleanup with proper Close methods

Installation

go get github.com/abitofhelp/servicelib/di

Quick Start

See the Basic Usage example for a complete, runnable example of how to use the dependency injection component.

API Documentation

Core Types
BaseContainer

The foundation container that provides common functionality.

type BaseContainer[C any] struct {
    // Internal fields
}
GenericAppContainer

A generic container for applications following a layered architecture.

type GenericAppContainer[R any, D any, A any, C any] struct {
    *BaseContainer[C]
    // Internal fields
}
Container

A non-generic container for backward compatibility.

type Container struct {
    *BaseContainer[interface{}]
}
Key Methods
NewBaseContainer

Creates a new base dependency injection container.

func NewBaseContainer[C any](ctx context.Context, logger *zap.Logger, cfg C) (*BaseContainer[C], error)
NewGenericAppContainer

Creates a new generic application container.

func NewGenericAppContainer[R any, D any, A any, C any](
    ctx context.Context,
    logger *zap.Logger,
    cfg C,
    connectionString string,
    initRepo AppRepositoryInitializer[R],
    initDomainService GenericDomainServiceInitializer[R, D],
    initAppService GenericApplicationServiceInitializer[R, D, A],
) (*GenericAppContainer[R, D, A, C], error)
NewContainer

Creates a new generic dependency injection container (for backward compatibility).

func NewContainer(ctx context.Context, logger *zap.Logger, cfg interface{}) (*Container, error)

Examples

For complete, runnable examples, see the following directories in the EXAMPLES directory:

  • Basic Usage - Shows basic usage of the dependency injection container
  • Generic Container - Shows how to use the generic container with type safety
  • Service Container - Shows how to use the service container for more complex applications

Best Practices

  1. Use Type Parameters: Leverage Go generics for type safety when possible
  2. Follow Layered Architecture: Organize code into repositories, domain services, and application services
  3. Inject Dependencies: Pass dependencies through constructors rather than creating them inside components
  4. Close Resources: Always call Close() on containers when they're no longer needed
  5. Use Context: Pass context through the container to enable proper cancellation and timeouts

Troubleshooting

Common Issues
Circular Dependencies

If you encounter circular dependencies (A depends on B, which depends on A):

  • Refactor your code to break the cycle
  • Consider introducing an interface to decouple components
  • Use a mediator pattern to handle communication between components
Memory Leaks

If resources aren't being cleaned up properly:

  • Ensure you're calling Close() on the container when it's no longer needed
  • Implement Close() methods on your custom types that need resource cleanup
  • Use defer to ensure Close() is called even if errors occur
  • Logging - Logging component used by the DI container
  • Config - Configuration management that works well with DI
  • DB - Database utilities that can be integrated with DI containers

Contributing

Contributions to this component are welcome! Please see the Contributing Guide for more information.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Overview

Package di provides a generic dependency injection container that can be used across different applications.

Package di provides a generic dependency injection container that can be used across different applications.

Package di provides generic database initializers that can be used across different applications.

Package di provides a comprehensive dependency injection framework for Go applications.

This package implements a flexible dependency injection system that helps manage application dependencies and promotes loose coupling between components. It supports various application architectures, with special focus on Domain-Driven Design (DDD) and Clean Architecture patterns.

Dependency injection is a design pattern that allows the separation of object creation from object usage, making code more modular, testable, and maintainable. This package provides containers that manage the lifecycle of dependencies and their relationships.

Key features:

  • Generic containers that work with any configuration type
  • Support for layered architecture (repositories, domain services, application services)
  • Type-safe dependency management using Go generics
  • Integration with logging, validation, and context management
  • Resource lifecycle management with proper cleanup
  • Thread-safe operation for concurrent applications

The package provides several container types for different use cases:

  • BaseContainer: A foundational container with basic dependencies
  • Container: A backward-compatible container using interface{} types
  • GenericAppContainer: A type-safe container for layered applications
  • RepositoryContainer: A specialized container for repository management
  • ServiceContainer: A container focused on service management

Example usage for a simple application:

// Create a container with application configuration
container, err := di.NewContainer(ctx, logger, appConfig)
if err != nil {
    log.Fatalf("Failed to create container: %v", err)
}
defer container.Close()

// Use the container to access dependencies
validator := container.GetValidator()
logger := container.GetLogger()

Example usage for a layered application:

// Create a generic container with typed dependencies
container, err := di.NewGenericAppContainer(
    ctx,
    logger,
    appConfig,
    connectionString,
    initUserRepository,
    initUserDomainService,
    initUserApplicationService,
)
if err != nil {
    log.Fatalf("Failed to create container: %v", err)
}
defer container.Close()

// Access typed dependencies
userRepo := container.GetRepository()
userService := container.GetApplicationService()

The package is designed to be extended for specific application needs. Custom containers can be created by embedding the provided containers and adding application-specific dependencies and initialization logic.

Package di provides a generic dependency injection container that can be used across different applications.

Package di provides a generic dependency injection container that can be used across different applications.

Package di provides generic repository interfaces that can be used across different applications.

Package di provides a generic dependency injection container that can be used across different applications.

Package di provides repository initializers for different database types.

Package di provides a generic dependency injection container that can be used across different applications.

Index

Constants

View Source
const DefaultTimeout = 30 * time.Second

Default timeout for database operations

Variables

This section is empty.

Functions

func GenericMongoInitializer

func GenericMongoInitializer(
	ctx context.Context,
	uri string,
	databaseName string,
	collectionName string,
	zapLogger *zap.Logger,
) (interface{}, error)

GenericMongoInitializer initializes a MongoDB collection and returns it This can be used by applications to create their own repository initializers

func GenericPostgresInitializer

func GenericPostgresInitializer(
	ctx context.Context,
	dsn string,
	zapLogger *zap.Logger,
) (interface{}, error)

GenericPostgresInitializer initializes a PostgreSQL connection pool and returns it This can be used by applications to create their own repository initializers

func GenericSQLiteInitializer

func GenericSQLiteInitializer(
	ctx context.Context,
	uri string,
	zapLogger *zap.Logger,
) (interface{}, error)

GenericSQLiteInitializer initializes a SQLite database connection and returns it This can be used by applications to create their own repository initializers

func MongoDBInitializer

func MongoDBInitializer(
	ctx context.Context,
	uri string,
	databaseName string,
	collectionName string,
	logger *zap.Logger,
) (*mongo.Collection, error)

MongoDBInitializer initializes a MongoDB client and collection

func PostgresInitializer

func PostgresInitializer(
	ctx context.Context,
	dsn string,
	logger *zap.Logger,
) (*pgxpool.Pool, error)

PostgresInitializer initializes a PostgreSQL connection pool

func SQLiteInitializer

func SQLiteInitializer(
	ctx context.Context,
	uri string,
	logger *zap.Logger,
) (*sql.DB, error)

SQLiteInitializer initializes a SQLite database connection

Types

type AppRepositoryInitializer

type AppRepositoryInitializer[T any] func(ctx context.Context, connectionString string, logger *zap.Logger) (T, error)

AppRepositoryInitializer is a function type that initializes a repository

type ApplicationService

type ApplicationService interface {
	// GetID returns the application service ID
	GetID() string
}

ApplicationService is a generic interface for application services

type ApplicationServiceInitializerFunc

type ApplicationServiceInitializerFunc[R Repository, D DomainService, A ApplicationService] func(
	domainService D,
	repository R,
) (A, error)

ApplicationServiceInitializerFunc is a function type that initializes an application service

type BaseContainer

type BaseContainer[C any] struct {
	// contains filtered or unexported fields
}

BaseContainer is a generic dependency injection container that can be embedded in other containers

func NewBaseContainer

func NewBaseContainer[C any](ctx context.Context, logger *zap.Logger, cfg C) (*BaseContainer[C], error)

NewBaseContainer creates a new base dependency injection container

func (*BaseContainer[C]) Close

func (c *BaseContainer[C]) Close() error

Close closes all resources

func (*BaseContainer[C]) GetConfig

func (c *BaseContainer[C]) GetConfig() C

GetConfig returns the configuration

func (*BaseContainer[C]) GetContext

func (c *BaseContainer[C]) GetContext() context.Context

GetContext returns the context

func (*BaseContainer[C]) GetContextLogger

func (c *BaseContainer[C]) GetContextLogger() *logging.ContextLogger

GetContextLogger returns the context logger

func (*BaseContainer[C]) GetLogger

func (c *BaseContainer[C]) GetLogger() *zap.Logger

GetLogger returns the logger

func (*BaseContainer[C]) GetValidator

func (c *BaseContainer[C]) GetValidator() *validator.Validate

GetValidator returns the validator

type Container

type Container struct {
	*BaseContainer[interface{}]
}

Container is a generic dependency injection container for backward compatibility It uses the BaseContainer with an interface{} config type

func NewContainer

func NewContainer(ctx context.Context, logger *zap.Logger, cfg interface{}) (*Container, error)

NewContainer creates a new generic dependency injection container This function is kept for backward compatibility

func (*Container) GetRepositoryFactory

func (c *Container) GetRepositoryFactory() interface{}

GetRepositoryFactory returns the repository factory This is a placeholder method that should be overridden by derived containers

type DomainService

type DomainService interface {
	// GetID returns the domain service ID
	GetID() string
}

DomainService is a generic interface for domain services

type DomainServiceInitializerFunc

type DomainServiceInitializerFunc[R Repository, D DomainService] func(repository R) (D, error)

DomainServiceInitializerFunc is a function type that initializes a domain service

type GenericAppContainer

type GenericAppContainer[R any, D any, A any, C any] struct {
	*BaseContainer[C]
	// contains filtered or unexported fields
}

GenericAppContainer is a generic dependency injection container for any application

func NewGenericAppContainer

func NewGenericAppContainer[R any, D any, A any, C any](
	ctx context.Context,
	logger *zap.Logger,
	cfg C,
	connectionString string,
	initRepo AppRepositoryInitializer[R],
	initDomainService GenericDomainServiceInitializer[R, D],
	initAppService GenericApplicationServiceInitializer[R, D, A],
) (*GenericAppContainer[R, D, A, C], error)

NewGenericAppContainer creates a new generic application container

func (*GenericAppContainer[R, D, A, C]) Close

func (c *GenericAppContainer[R, D, A, C]) Close() error

Close closes all resources

func (*GenericAppContainer[R, D, A, C]) GetApplicationService

func (c *GenericAppContainer[R, D, A, C]) GetApplicationService() A

GetApplicationService returns the application service

func (*GenericAppContainer[R, D, A, C]) GetDomainService

func (c *GenericAppContainer[R, D, A, C]) GetDomainService() D

GetDomainService returns the domain service

func (*GenericAppContainer[R, D, A, C]) GetRepository

func (c *GenericAppContainer[R, D, A, C]) GetRepository() R

GetRepository returns the repository

func (*GenericAppContainer[R, D, A, C]) GetRepositoryFactory

func (c *GenericAppContainer[R, D, A, C]) GetRepositoryFactory() interface{}

GetRepositoryFactory returns the repository as an interface{}

type GenericApplicationServiceInitializer

type GenericApplicationServiceInitializer[R any, D any, A any] func(domainService D, repository R) (A, error)

GenericApplicationServiceInitializer is a function type that initializes an application service

type GenericDomainServiceInitializer

type GenericDomainServiceInitializer[R any, D any] func(repository R) (D, error)

GenericDomainServiceInitializer is a function type that initializes a domain service

type GenericRepositoryContainer

type GenericRepositoryContainer[T any, C any] struct {
	*BaseContainer[C]
	// contains filtered or unexported fields
}

GenericRepositoryContainer is a generic dependency injection container for any repository type

func NewGenericRepositoryContainer

func NewGenericRepositoryContainer[T any, C any](
	ctx context.Context,
	logger *zap.Logger,
	cfg C,
	entityType string,
	initRepo GenericRepositoryInitializer[T],
) (*GenericRepositoryContainer[T, C], error)

NewGenericRepositoryContainer creates a new generic repository container

func (*GenericRepositoryContainer[T, C]) Close

func (c *GenericRepositoryContainer[T, C]) Close() error

Close closes all resources

func (*GenericRepositoryContainer[T, C]) GetRepository

func (c *GenericRepositoryContainer[T, C]) GetRepository() T

GetRepository returns the repository

func (*GenericRepositoryContainer[T, C]) GetRepositoryFactory

func (c *GenericRepositoryContainer[T, C]) GetRepositoryFactory() interface{}

GetRepositoryFactory returns the repository as an interface{}

type GenericRepositoryInitializer

type GenericRepositoryInitializer[T any] func(ctx context.Context, connectionString string, logger *zap.Logger) (T, error)

GenericRepositoryInitializer is a function type that initializes a repository

type Repository

type Repository interface {
	// GetID returns the repository ID
	GetID() string
}

Repository is a generic interface for repositories

type RepositoryContainer

type RepositoryContainer[T any] struct {
	// contains filtered or unexported fields
}

RepositoryContainer is a generic dependency injection container for any repository type

func NewRepositoryContainer

func NewRepositoryContainer[T any](
	ctx context.Context,
	logger *zap.Logger,
	cfg config.Config,
	entityType string,
	initRepo RepositoryInitializerFunc[T],
) (*RepositoryContainer[T], error)

NewRepositoryContainer creates a new repository container

func (*RepositoryContainer[T]) Close

func (c *RepositoryContainer[T]) Close() error

Close closes all resources

func (*RepositoryContainer[T]) GetConfig

func (c *RepositoryContainer[T]) GetConfig() config.Config

GetConfig returns the configuration

func (*RepositoryContainer[T]) GetContext

func (c *RepositoryContainer[T]) GetContext() context.Context

GetContext returns the context

func (*RepositoryContainer[T]) GetLogger

func (c *RepositoryContainer[T]) GetLogger() *zap.Logger

GetLogger returns the logger

func (*RepositoryContainer[T]) GetRepository

func (c *RepositoryContainer[T]) GetRepository() T

GetRepository returns the repository

func (*RepositoryContainer[T]) GetRepositoryFactory

func (c *RepositoryContainer[T]) GetRepositoryFactory() interface{}

GetRepositoryFactory returns the repository as an interface{}

type RepositoryInitializerFunc

type RepositoryInitializerFunc[T any] func(
	ctx context.Context,
	connectionString string,
	databaseName string,
	collectionName string,
	logger *zap.Logger,
) (T, error)

RepositoryInitializerFunc is a function type that initializes a repository

type ServiceContainer

type ServiceContainer[R Repository, D DomainService, A ApplicationService, C config.Config] struct {
	*BaseContainer[C]
	// contains filtered or unexported fields
}

ServiceContainer is a generic dependency injection container for services

func NewServiceContainer

func NewServiceContainer[R Repository, D DomainService, A ApplicationService, C config.Config](
	ctx context.Context,
	logger *zap.Logger,
	cfg C,
	repository R,
	initDomainService DomainServiceInitializerFunc[R, D],
	initAppService ApplicationServiceInitializerFunc[R, D, A],
) (*ServiceContainer[R, D, A, C], error)

NewServiceContainer creates a new service container

func (*ServiceContainer[R, D, A, C]) Close

func (c *ServiceContainer[R, D, A, C]) Close() error

Close closes all resources

func (*ServiceContainer[R, D, A, C]) GetApplicationService

func (c *ServiceContainer[R, D, A, C]) GetApplicationService() A

GetApplicationService returns the application service

func (*ServiceContainer[R, D, A, C]) GetDomainService

func (c *ServiceContainer[R, D, A, C]) GetDomainService() D

GetDomainService returns the domain service

func (*ServiceContainer[R, D, A, C]) GetRepository

func (c *ServiceContainer[R, D, A, C]) GetRepository() R

GetRepository returns the repository

func (*ServiceContainer[R, D, A, C]) GetRepositoryFactory

func (c *ServiceContainer[R, D, A, C]) GetRepositoryFactory() interface{}

GetRepositoryFactory returns the repository as an interface{}

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL