The main objective of this repository is to compose a versatile architecture.
It's a simple Cobra CLI application and displays a summary of the target website.
Clean architecture, testing of command lined, switching production or development environments, and abstraction of data sources through dependency injection (DI). It includes the base elements of any project.
This is published as a record of my Golang learning.
- Modern CLI - cobra
- Environment Variables - GoDotEnv
- DI (Dependency Injection) Container - dig
- Validator - ozzo-validation
Detail : go.mod
Create go.sum:
go mod tidy
go run ./app/cli/main.go summary [Target URL]
Response:
title : [string]
H1 : [string]
Keeping the nature of the Cobra code that exposes the cmd as a variable, adding application logic in a form that is easy to separate.
flowchart LR
subgraph Controller
id1["cobra (app/cli/cmd)"]
end
subgraph Application
core/app
end
subgraph Domain
core/url
end
subgraph DataStore
core/url/provider
end
Controller --- Application
Application --- Domain
Application --- DataStore
Domain --- DataStore
classDiagram
Url -- App
Url -- Provider
Provider -- App
Provider <|.. WebProvider : Realization
Provider <|.. InMemDummyProvider : Realization
class App {
+CmdSummary()
}
class Url {
-validate()
}
class Provider
<<interface>> Provider
Provider : +ReadBody()
class WebProvider {
+ReadBody()
}
class InMemDummyProvider {
+ReadBody()
}
The application depends on a data store, but uses a DI container to ease changing. In the case of this program, the data store is the Web, but a database is typically used.
Initialize DI Container (app/cli/cmd/root.go):
// Initialize DI container
diContainer = *dig.New()
diContainer.Provide(app.NewApp)
// Register UrlProvider to use with Container
// Switch data source external or dummy
if env == "production" {
diContainer.Provide(url.NewWebProvider)
return
}
diContainer.Provide(url.NewInMemDummyProvider)
Use Container (app/cli/cmd/summary.go):
// Application Logic
// Create app Instance via DI Container
diContainer.Invoke(
func(a *app.App) {
a.CmdSummary(args)
},
)
To switch environments, modify the .env
file in the root directory as you would in a typical project.
If this element is development, the data source is in-memory. (If production, the data source is web.)
development:
APP_ENV=development
production:
APP_ENV=production
If nothing is specified, Switch to development env.
go test ./app/cli/cmd -v
In the go test
command, the environment is always development. This is because the current directory is the directory to be tested, and therefore the .env
fails to be retrieved.
- More abstraction