wotop

package module
v0.15.3 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2025 License: MIT Imports: 10 Imported by: 0

README ¶

Overview

WOTOP is an open‑source Go framework designed to accelerate backend development with modern architectural patterns. It brings together:

  • Clean Architecture for strict separation of business logic and infrastructure layers
  • Domain‑Driven Design (DDD) to model complex domains with clarity
  • Event‑Driven Microservices for loosely‑coupled, asynchronous communication
  • Cloud‑Native Microservices optimized for containerized, orchestrated environments

Additionally, WOTOP integrates core patterns and tools out of the box:

  • CQRS (Command Query Responsibility Segregation)
  • RabbitMQ message broker
  • Event Sourcing for append‑only event storage

🎯 Features

  • Layered Clean Architecture
    Enforces the Dependency Rule, isolating Use Cases, Entities, and Interfaces for maximum testability and maintainability.

  • Domain‑Driven Design
    Implements Aggregates, Repositories, and Bounded Contexts so your code mirrors real‑world domain concepts.

  • Event‑Driven Communication
    Built‑in event bus with publish/subscribe support for decoupled services.

  • Cloud‑Native Ready
    Services are containerized and Kubernetes‑friendly, with support for self‑healing, auto‑scaling, and sidecar integrations.

  • CQRS
    Separates read and write workloads into dedicated models for better performance and scalability.

  • RabbitMQ Integration
    Reliable, configurable message broker support for asynchronous workflows.

  • Event Sourcing
    Append‑only event store that lets you reconstruct any entity’s state at any point in time.


🚀 Quick Start

WOTOP CLI is a lightweight CLI tool for scaffolding Go backend code. It provides two main commands:

  • usecase – generates a usecase directory with inport.go, outport.go, and interactor.go files.
  • entity – generates an entity file under your models with struct definitions and helper methods.

This README covers:

  1. Installation
  2. Command: wotop usecase
  3. Command: wotop entity
  4. Examples

Installation

Install globally

# Installs to $GOBIN or $GOPATH/bin
go install github.com/a-aslani/wotop/cmd/wotop@latest
go get -u github.com/a-aslani/wotop@latest

Make sure $GOBIN (or $HOME/go/bin) is in your PATH so you can run wotop from anywhere.


usecase Command

wotop usecase <domain> <name>

<domain>

  • The parent domain under internal/.
  • E.g. if you pass product, files go under internal/product.

<name>

  • The usecase identifier.
  • The folder name is converted to snake_case.
  • The Go package inside will match that snake_case folder.

What it creates

Given:

wotop usecase product getUserInfo

It will create:

internal/
└── product/
    └── usecase/
        └── get_user_info/
            ├── inport.go
            ├── outport.go
            └── interactor.go

inport.go

package get_user_info

import "github.com/a-aslani/wotop"

type Inport = wotop.Inport[InportRequest, InportResponse]

type InportRequest struct {
    // request fields
}

type InportResponse struct {
    // response fields
}

outport.go

package get_user_info

type Outport interface {
    // define methods to call downstream adapters
}

interactor.go

package get_user_info

import "context"

type interactor struct {
    outport Outport
}

func NewUsecase(outport Outport) Inport {
    return &interactor{outport: outport}
}

func (i interactor) Execute(ctx context.Context, req InportRequest) (*InportResponse, error) {
    res := InportResponse{}
    // TODO: implement usecase logic
    return &res, nil
}

entity Command

wotop entity <domain> <name>

<domain>

  • The parent domain under internal/.
  • E.g. product → will place files in internal/product/model/entity.

<name>

  • The entity name in camelCase, snake_case, or PascalCase.
  • Internally the struct name is converted to PascalCase.
  • The file name is generated in snake_case.

What it creates

Given:

wotop entity product userState

It will create:

internal/
└── product/
    └── model/
        └── entity/
            └── user_state.go

user_state.go

package entity

type UserState struct {}

type UserStateFilter struct {}

type CreateUserStateRequest struct {}

func (c CreateUserStateRequest) Validate() error {
    // TODO: add validation logic
    return nil
}

func NewUserState(req CreateUserStateRequest) (*UserState, error) {
    // TODO: add creation logic
    return &UserState{}, nil
}

Documentation ¶

Index ¶

Constants ¶

This section is empty.

Variables ¶

This section is empty.

Functions ¶

func RunTestcaseScenarios ¶

func RunTestcaseScenarios[REQUEST, RESPONSE, OUTPORT any](t *testing.T, f func(o OUTPORT) Inport[REQUEST, RESPONSE], scenarioList ...TestScenario[REQUEST, RESPONSE, OUTPORT])

RunTestcaseScenarios runs a list of test scenarios for an Inport.

This function executes each test scenario in parallel, invoking the provided Inport function with the given outport and request. It then asserts the response and error against the expected values.

Type Parameters:

  • REQUEST: The type of the request object.
  • RESPONSE: The type of the response object.
  • OUTPORT: The type of the outport dependency.

Parameters:

  • t: The testing object used to manage test execution.
  • f: A function that takes an OUTPORT and returns an Inport instance.
  • scenarioList: A variadic list of TestScenario objects to be executed.

Types ¶

type ApplicationData ¶

type ApplicationData struct {
	AppName       string `json:"app_name"`        // The name of the application.
	AppInstanceID string `json:"app_instance_id"` // A unique identifier for the application instance.
	StartTime     string `json:"start_time"`      // The start time of the application instance.
}

ApplicationData represents metadata about the application instance.

Fields:

  • AppName: The name of the application.
  • AppInstanceID: A unique identifier for the application instance.
  • StartTime: The start time of the application instance in the format "YYYY-MM-DD HH:MM:SS".

func NewApplicationData ¶

func NewApplicationData(appName string) ApplicationData

NewApplicationData creates a new ApplicationData instance with the given application name.

Parameters:

  • appName: The name of the application.

Returns:

  • An ApplicationData instance populated with the application name, a generated instance ID, and the current start time.

type BaseConsumer ¶

type BaseConsumer struct {
	// contains filtered or unexported fields
}

BaseConsumer provides a base implementation for use case registration in consumers.

func (BaseConsumer) AddUsecase ¶

func (b BaseConsumer) AddUsecase(inports ...any)

AddUsecase registers one or more use cases.

Parameters:

  • inports: Variadic parameter representing the use cases to be registered.

func (BaseConsumer) GetUsecase ¶

func (b BaseConsumer) GetUsecase(nameStructType any) (any, error)

GetUsecase retrieves a registered use case by its type.

Parameters:

  • nameStructType: The type of the use case to retrieve.

Returns:

  • The registered use case, or an error if it is not found.

type BaseController ¶

type BaseController struct {
	// contains filtered or unexported fields
}

BaseController provides a base implementation for use case registration.

func (*BaseController) AddUsecase ¶

func (r *BaseController) AddUsecase(inports ...any)

AddUsecase registers one or more use cases.

Parameters:

  • inports: Variadic parameter representing the use cases to be registered.

func (*BaseController) GetUsecase ¶

func (r *BaseController) GetUsecase(nameStructType any) (any, error)

GetUsecase retrieves a registered use case by its type.

Parameters:

  • nameStructType: The type of the use case to retrieve.

Returns:

  • The registered use case, or an error if it is not found.

type ControllerRegisterer ¶

type ControllerRegisterer interface {
	ControllerStarter
	UsecaseRegisterer

	// RegisterRouter sets up the router for the controller.
	RegisterRouter()

	// RegisterMetrics sets up metrics for the service.
	//
	// Parameters:
	//   - serviceName: The name of the service for which metrics are being registered.
	RegisterMetrics(serviceName string)
}

ControllerRegisterer defines an interface that combines controller starting, use case registration, and additional functionalities like router and metrics registration.

type ControllerStarter ¶

type ControllerStarter interface {
	// Start initializes and starts the controller.
	Start()
}

ControllerStarter defines an interface for starting a controller.

type Inport ¶

type Inport[REQUEST, RESPONSE any] interface {
	// Execute processes the given request and returns a response or an error.
	//
	// Parameters:
	//   - ctx: The context for managing request-scoped values, deadlines, and cancellations.
	//   - req: The request object of type REQUEST.
	//
	// Returns:
	//   - A pointer to the response object of type RESPONSE, or an error if the execution fails.
	Execute(ctx context.Context, req REQUEST) (*RESPONSE, error)
}

Inport defines a generic interface for use cases with a request and response type.

Type Parameters:

  • REQUEST: The type of the request object.
  • RESPONSE: The type of the response object.

func GetInport ¶

func GetInport[Req, Res any](usecase any, err error) Inport[Req, Res]

GetInport retrieves and validates an Inport instance from a use case.

This function ensures that the provided use case can be cast to the Inport interface with the specified request and response types. If the use case is invalid or cannot be cast, the function logs an error message and terminates the program.

Type Parameters:

  • Req: The type of the request object.
  • Res: The type of the response object.

Parameters:

  • usecase: The use case to be cast to the Inport interface.
  • err: An error object that, if non-nil, will cause the program to terminate.

Returns:

  • An Inport instance with the specified request and response types.

type RabbitmqConsumerRegisterer ¶

type RabbitmqConsumerRegisterer interface {
	UsecaseRegisterer

	// Start initializes and starts the RabbitMQ consumer.
	Start()

	// ConsumeMessage processes a RabbitMQ message.
	//
	// Parameters:
	//   - index: The index of the message.
	//   - msg: The RabbitMQ message to be consumed.
	ConsumeMessage(index int, msg *amqp.Delivery)
}

RabbitmqConsumerRegisterer defines an interface for registering and consuming RabbitMQ messages.

type Runner ¶

type Runner[T any] interface {
	// Run executes the task with the provided configuration.
	//
	// Parameters:
	//   - cfg: A pointer to the configuration object of type T.
	//
	// Returns:
	//   - An error if the task execution fails, otherwise nil.
	Run(cfg *T) error
}

Runner defines a generic interface for running a task with a given configuration.

Type Parameters:

  • T: The type of the configuration object.

type ServiceRegisterer ¶

type ServiceRegisterer interface {
	UsecaseRegisterer

	// Start initializes and starts the service.
	Start()
}

ServiceRegisterer defines an interface for registering and starting services.

type TestScenario ¶

type TestScenario[REQUEST, RESPONSE, OUTPORT any] struct {
	Name           string    // The name of the test case.
	InportRequest  REQUEST   // The input request to be passed to the Inport.
	InportResponse *RESPONSE // The expected response from the Inport.
	Outport        OUTPORT   // The outport dependency to be used in the test case.
	ExpectedError  error     // The expected error, if any, from the Inport execution.
}

TestScenario represents a test case scenario for testing an Inport.

Type Parameters:

  • REQUEST: The type of the request object.
  • RESPONSE: The type of the response object.
  • OUTPORT: The type of the outport dependency.

type UsecaseRegisterer ¶

type UsecaseRegisterer interface {
	// AddUsecase registers one or more use cases.
	//
	// Parameters:
	//   - inports: Variadic parameter representing the use cases to be registered.
	AddUsecase(inports ...any)

	// GetUsecase retrieves a registered use case by its type.
	//
	// Parameters:
	//   - nameStructType: The type of the use case to retrieve.
	//
	// Returns:
	//   - The registered use case, or an error if it is not found.
	GetUsecase(nameStructType any) (any, error)
}

UsecaseRegisterer defines an interface for registering and retrieving use cases.

func NewBaseConsumer ¶

func NewBaseConsumer() UsecaseRegisterer

NewBaseConsumer creates a new instance of BaseConsumer.

Returns:

  • A UsecaseRegisterer instance for registering use cases.

func NewBaseController ¶

func NewBaseController() UsecaseRegisterer

NewBaseController creates a new instance of BaseController.

Returns:

  • A UsecaseRegisterer instance for registering use cases.

func NewBaseService ¶

func NewBaseService() UsecaseRegisterer

NewBaseService creates a new instance of BaseConsumer for services.

Returns:

  • A UsecaseRegisterer instance for registering use cases.

Directories ¶

Path Synopsis
cmd
wotop command
examples
model
Package password is a generated GoMock package.
Package password is a generated GoMock package.
mocks
Package mockrecaptcha is a generated GoMock package.
Package mockrecaptcha is a generated GoMock package.

Jump to

Keyboard shortcuts

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