Go-Workflow Go Report Card codebeat badge codecov


The project status is WIP (Work in progress) which means the author continously evaluate and improve the project.

Pragmatic Golang RESTful Server Implementation. The project using typical-go as its build-tool.

  • Application
    • Go-Standards Project Layout
    • Environment Variable Configuration
    • Health-Check and Debug API
    • Graceful Shutdown
  • Layered architecture
    • SOLID Principle
    • Dependency Injection (using @ctor annotation)
    • ORMHate
    • Database Transaction
  • HTTP Server
    • Echo framework
    • Server Side Caching
      • Cache but revalidate (Header Cache-Control: no-cache)
      • Set Expiration Time (Header Cache-Control: max-age=120)
      • Return 304 if not modified (Header If-Modified-Since: Sat, 31 Oct 2020 10:28:02 GMT)
    • Request ID in logger (Header X-Request-Id: xxx)
  • RESTful
    • Create Resource (POST verb)
    • Update Resource (PUT verb)
    • Partially Update Resource (PATCH verb)
    • Find Resource (GET verb)
      • Offset Pagination (Query param ?limit=100&offset=0)
      • Sorting (Query param ?sort=-title,created_at)
      • Total count (Header X-Total-Count: 99)
    • Check resource (HEAD verb)
    • Delete resource (DELETE verb, idempotent)
  • Testing
    • Table Driven Test
    • Mocking (using @mock annotation)
  • Others
    • Database migration and seed tool
    • Generate code, .env file and according the configuration (using @envconfig annotation)
    • Generate code for repository layer (using @entity annotation)
    • Releaser

Run/Test Project

Copy .env.sample for working configuration

cp .env.sample .env    # copy the working .env

Setup the local environment

./typicalw docker up   # equivalent with `docker-compose up -d`
./typicalw reset       # reset infra: drop, create and migrate postgres database 

Run application:

./typicalw run         # run the application

Test application:

./typicalw test        # run test 

Project descriptor at tools/typical-build/typical-build.go

var descriptor = typgo.Descriptor{
  ProjectName:    "typical-rest-server",
  ProjectVersion: "0.9.7",
  Tasks: []typgo.Tasker{
    // tasks ... 

Project Layout

Typical-Rest encourage standard go project layout

Source codes:

Others directory:

  • tools Supporting tool for the project e.g. Build Tool
  • api Any related scripts for API e.g. api-model script (swagger, raml, etc) or client script
  • databases Any related scripts for Databases e.g. migration scripts and seed data

Layered Architecture

Typical-Rest encourage layered architecture as most adoptable architectural pattern

  • Presentation Layer at internal/app/controller
    • Parsing the request
    • Sending response
  • Logic Layer at internal/app/service
    • Intermediary between controller (end-point) and repository (data)
    • Logic of controller
    • Data Validation
  • Data Access Layer at internal/app/entity (database) or internal/app/model (business)
    • No logic except operation to database
    • Repository pattern for Database entity or Business Model

Dependency Injection

Typical-Rest encourage dependency injection using uber-dig and annotations (@ctor).

// NewConn ... 
// @ctor
func NewConn() *sql.DB{

Application Config

Typical-Rest encourage application config with environment variables using envconfig and annotation (@envconfig).

type (
  // AppCfg application configuration
  // @envconfig (prefix:"APP")
  AppCfg struct {
    Address string `envconfig:"ADDRESS" default:":8089" required:"true"`
    Debug   bool   `envconfig:"DEBUG" default:"true"`

Generate usage documentation ( and .env file

// in typical-build

  DotEnv:   ".env",     // generate .env file
  UsageDoc: "", // generate


Typical-Rest encourage mocking using gomock and annotation(@mock).

  // Reader responsible to read
  // @mock
  Reader interface{
    Read() error

Mock class will be generated in *_mock package

Database Transaction

In Repository layer

func (r *RepoImpl) Delete(ctx context.Context) (int64, error) {
  txn, err := dbtxn.Use(ctx, r.DB) // use transaction if begin detected 
  if err != nil {                  // create transaction error
      return -1, err
  db := txn                     // transaction object or database connection
  // result, err := ...
  if err != nil {
      txn.SetError(err)            // set the error and plan for rollback
      return -1, err
  // ...

In Service layer

func (s *SvcImpl) SomeOperation(ctx context.Context) (err error){
  // begin the transaction 
  txn := dbtxn.Begin(&ctx)

  // commit/rollback in end function
  defer func(){ err = txn.Commit() }()
  // ...

Server-Side Cache

Use echo middleware to handling cache

cacheStore := &cachekit.Store{
  Client:        redis.NewClient(&redis.Options{Addr: "localhost:6379"}),
  DefaultMaxAge: 30 * time.Second,
  PrefixKey:     "cache_",

e := echo.New()
e.GET("/", handle, cacheStore.Middleware)





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

Expand ▾ Collapse ▴


Path Synopsis
Package service_mock is a generated GoMock package.
Package service_mock is a generated GoMock package.
Package repo_mock is a generated GoMock package.
Package repo_mock is a generated GoMock package.