• This repository has been archived on 21/May/2024
  • Stars
    star
    179
  • Rank 214,039 (Top 5 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Pragmatic Boilerplate for Golang RESTful Server Implementation

Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public. Go-Workflow Go Report Card codebeat badge codecov

typical-rest-server

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 USAGE.md according the configuration (using @envconfig annotation)
    • Generate code for repository layer
    • 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 -d  # equivalent with `docker-compose up -d`

# wait few seconds to make sure docker ready
./typicalw setup         # setup dependency e.g. mysql and postgres

Generate code by annotation (if any change required)

./typicalw generate

Build + 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
  • database Any related scripts for Databases e.g. migration scripts and seed data

Dependency Injection

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

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

Add import side-effect to make it work

import (
  _ "github.com/typical-go/typical-rest-server/internal/generated/ctor"
)

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 (USAGE.md) and .env file

// in typical-build

&typcfg.EnvconfigAnnot{
  DotEnv:   ".env",     // generate .env file
  UsageDoc: "USAGE.md", // generate USAGE.md
}

Add import side-effect to make it work

import(
  _ "github.com/typical-go/typical-rest-server/internal/generated/envcfg"
)

Mocking

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

type(
  // 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.AppendError(err)            // append error to 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)

References

Golang:

RESTful API:

License

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