Skip to content

Repository files navigation

common-template-golang

Language: English | 中文

A common module template for golang.

1. Code Structure

  • adapter/
    Adaptation layer code for external interaction, such as RESTful API definition and command line definition.

  • config/
    Configuration files (app.toml) and the SQLite schema (schema_sqlite.sql).

  • data Sqlite data file.

  • docs/
    Document directory generated by swagger.

  • domain/ Domain model definition and implementation.

  • infra/
    Infrastructure code that implements external dependencies, such as database access object, etc.

  • pkg/
    Functional packages, such as util functions, injection functions, dto definitions, etc.

  • service/
    Service layer code implements the main business processes.

  • CLAUDE.md
    Guidance for Claude Code (and other AI coding assistants) working in this repository: project overview, build/test commands, and non-obvious implementation details worth knowing before making changes.

  • Dockerfile
    Two-stage build: a builder stage compiles the app, and a final stage runs it on a slim base image.

  • go.mod, go.sum
    Go module definition and dependency lock files.

  • main.go Main program, code entrance.

  • README.md
    Project documentation.

This template follows the standard Go project layout, making it easy to start new Go modules with best practices.

2. How main.go wires components together

main.go doesn't do any setup itself — it just declares an ordered list of components and hands them to bootstrap.New()...Run(), which is the common startup/shutdown orchestrator shared by every service built on common-library-golang. Each component has an Init() (called in registration order at startup) and a Close() (called in reverse order at shutdown). Understanding this chain is the fastest way to understand what a new service generated from this template actually does when it starts.

bootstrap.New().
    Add(envComp.Component("config/app.toml")). // 1st - env
    Add(logComp.Component()).                  // 2nd - log
    AddParallel(dbComp.Component()).
    PreReady(initServices).
    Add(ginComp.Component(func(r *gin.Engine) {
        router = r
        adapter.Mount(r)
    })).
    Add(httpComp.Component(func() http.Handler { return router })).
    PostReady(func() { log.Infof("%s start successfully, ...", ...) }).
    Run()

Step by step:

  1. envComp.Component("config/app.toml") — must always be the first Add() call. Loads config/app.toml into the koanf config singleton (env.Env()), which every other component reads from during its own Init(). Close() is a no-op.

  2. logComp.Component() — must always be the second Add() call. Reads the [log] section (log.level, and optionally log.file.* for file-based rotation) and initializes the process-wide logger. Because it's closed last (LIFO), shutdown log messages are never lost.

  3. AddParallel(dbComp.Component()) — opens the database connection. This template uses dbsqlx/sqlite/component, which reads db.sqlite.path from config/app.toml and registers the connection as dbsqlx.Default(). AddParallel lets multiple independent components (e.g. a second data store, a cache client) initialize concurrently in the same phase — here there's only one, but a real project might add more alongside it. Swap this single line for dbsqlx/postgres/component to switch the template to Postgres.

  4. PreReady(initServices) — a custom hook (defined in this file, not a library component) that runs once env/log/db are ready but before the HTTP server starts accepting traffic. This is where dependency injection happens: DAOs are constructed on top of dbsqlx.Default(), wrapped in services, and published to the adapter layer via adapter.Svcs. Add a new entity to the template by extending this function the same way service.NewUserService(dao.NewUserDao(dbsqlx.Default())) is wired here. PreReady steps have no Close() — they're pure setup, not a component.

  5. ginComp.Component(func(r *gin.Engine) {...}) — creates the *gin.Engine (with CORS configured from cors.allow.origins.dev/.prod depending on app.env.value), then immediately calls the supplied closure. That closure captures the router into the var router *gin.Engine declared at the top of main() and calls adapter.Mount(r) to register every REST route. Close() is a no-op — the Gin engine itself holds no resources; the actual listener is owned by the next component.

  6. httpComp.Component(func() http.Handler { return router }) — starts the real HTTP listener on http.server.port, serving whatever http.Handler the closure returns. The closure is evaluated lazily at Init() time (not when Add() is called), which is why it's safe even though router is only assigned inside step 5's closure — by the time this component's Init() runs, step 5 has already completed. Close() gracefully shuts the server down within httpserver.DefaultShutdownTimeout.

  7. PostReady(func() {...}) — runs once, after every component above has initialized successfully and just before the process blocks waiting for a shutdown signal. This template logs the app name/version/environment/local IP here; use it for anything that should only happen once the service is fully up (e.g. registering with a service discovery system).

  8. Run() — executes all of the above in order, then calls shutdown.Wait() to block until an OS signal (or an internal shutdown.Trigger(), e.g. if the HTTP server dies unexpectedly) arrives. On shutdown, every component's Close() runs in LIFO order: HTTP server → Gin (no-op) → SQLite → log → env (no-op) — so in-flight requests get a chance to finish, the DB connection closes cleanly, and the very last thing written is the shutdown log line.

If Init() fails at any step (including a PreReady function returning a non-nil error), bootstrap logs the failure, rolls back every already-started component in LIFO order, and exits the process with code 1 — so a new service never ends up half-initialized.

3. How to run?

1. Update dependency

  • go mod tidy

2. Generate swagger files

  • swag init

visit http://localhost:8001/swagger/index.html

3. Test

  • go test ./... -cover

4. Build

  • go build

5. Run

  • ./template

About

A module template for golang.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages