Skip to content
This repository was archived by the owner on May 21, 2024. It is now read-only.

typical-go/typical-rest-server

Repository files navigation

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

About

Pragmatic Boilerplate for Golang RESTful Server Implementation

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 7