Skip to content

Commit

Permalink
Merge pull request #14 from abyssparanoia/refactor/readme
Browse files Browse the repository at this point in the history
Refactor/readme
  • Loading branch information
abyssparanoia authored Apr 27, 2019
2 parents 0d5db85 + 11039dd commit c2bc45d
Show file tree
Hide file tree
Showing 49 changed files with 193 additions and 174 deletions.
89 changes: 55 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
# rapid-go

## motivation

rapid-go is a boilerplate that accelerates API development based on layered architecture and clarifying responsibilities.

## stack

- golang 1.11
- mysql (cloud sql)
- golang 1.11 (I will actively raise go version)
- mysql (correspondence such as firestore is easy)
- Chi (as Router)
- squirrel (as query builder)
- sqlx (map the result of sql to an object)
- gin (for hot reload ,not framwork)
- docker
- mockgen (generate mock codes from inteface)
- zap (as logger)
- firebase auth (as authenticate service)

## local
## development

- package
- 実行するのは docker container の中なので関係ないが、vscode でローカルにパッケージがないとエラーでまくってうざいので、dep でローカルにライブラリをインストールすることをお勧めします。
- init

```bash
> cd api/src
> dep ensure
make init
```

- build

```bash
> docker-compose build
> make build
```

- start

```bash
> docker-compose up -d
> make start
> curl http://localhost:3001/ping
```

- stop

```bash
> make down
```

- generate mock from interface (service,domain/repository)
Expand All @@ -43,28 +56,36 @@
> make test
```

- request
- ローカル開発の際にはリクエストに毎度 auth のトークン入れるのはめんどくさいと思うので、ローカル環境のみ/noauth/v1 という感じで、noauth を挟むことで dummy の authID を入れてリクエストを通せる。

## develop flow

- model を書く
- DBschema と一致するであろう entitiy
- repository を書く
- DB や外部 API に対してクエリーやリクエストを投げる処理を書く
- データの CRUD のみを扱う
- service を書く
- ロジックをメインに書く
- 権限コントロールなども行う
- 複数の repository を利用することも多々ある
- ここで API を叩いたりクエリーを書いてはいけない
- handler を書く

- リクエストとレスポンスの定義を行う
- URL パラメータや auth の uid 等もここで取得する。
- えた値を全て service の関数の引数に入れて、service を呼ぶ。
- 必ずサービスは一つ

- dependency や routing は適宜追加してください。
- 新しいライブラリーを使いたくなった場合は都度相談して利用すること(ほぼないはず)
- むやみに goroutine を使わない。(特に DB 周りは気をつけないとすぐに connection が枯渇する)
## about layer

### infrastructure

- data layer
- It is responsibility to handle the data
- interested in database etc.

#### entity

- struct for setting the result of SQL etc....

#### infra/repository

- write the actual data manipulation process

### domain

#### model

- domain model

#### domain/repository

- write interface for infrastructure/repository and convert entity to domain

### service layer

- write application logic using repository

### handler

- write the process about request and response
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
Expand Down Expand Up @@ -81,6 +82,7 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
Expand All @@ -94,6 +96,7 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/unrolled/render v1.0.0 h1:XYtvhA3UkpB7PqkvhUFYmpKD55OudoIeygcfus4vcd4=
github.com/unrolled/render v1.0.0/go.mod h1:tu82oB5W2ykJRVioYsB+IQKcft7ryBr7w12qMBUPyXg=
Expand Down
8 changes: 4 additions & 4 deletions routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import (
"github.com/go-chi/chi"
)

// Routing ... ルーティング設定
// Routing ... define routing
func Routing(r chi.Router, d Dependency) {

// request log
r.Use(log.Middleware)

// アクセスコントロール
// access control
r.Use(middleware.AccessControl)

// 認証なし(Stagingのみ)
// no need to authenticate for development
if config.IsEnvDeveloping() {
r.Route("/noauth/v1", func(r chi.Router) {
r.Use(d.DummyFirebaseAuth.Handle)
Expand All @@ -28,7 +28,7 @@ func Routing(r chi.Router, d Dependency) {
})
}

// 認証あり
// need to authenticate for production
r.Route("/v1", func(r chi.Router) {
r.Use(d.FirebaseAuth.Handle)
r.Use(d.HTTPHeader.Handle)
Expand Down
2 changes: 1 addition & 1 deletion src/config/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ package config
import "time"

const (
// HTTPRequestTimeout ... デフォルトのHTTPリクエストタイムアウト
// HTTPRequestTimeout ... timeout for http request
HTTPRequestTimeout time.Duration = 20
)
6 changes: 3 additions & 3 deletions src/config/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import (
"os"
)

// IsEnvDeveloping ... 現在の環境がdevelopか判定する
// IsEnvDeveloping ... development
func IsEnvDeveloping() bool {
return os.Getenv("ENV") == "develop"
}

// IsEnvStaging ... 現在の環境がステージングか判定する
// IsEnvStaging ... staging
func IsEnvStaging() bool {
return os.Getenv("ENV") == "staging"
}

// IsEnvProduction ... 現在の環境が本番か判定する
// IsEnvProduction ... production
func IsEnvProduction() bool {
return os.Getenv("ENV") == "production"
}
10 changes: 5 additions & 5 deletions src/domain/model/response.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package model

// ResponseOK ... 成功レスポンス
// ResponseOK ... success response
type ResponseOK struct {
Status int `json:"status"`
}

// NewResponseOK ... 成功レスポンスを取得する
// NewResponseOK ... get success response
func NewResponseOK(status int) *ResponseOK {
return &ResponseOK{
Status: status,
}
}

// ResponseError ... エラーレスポンス
// ResponseError ... error response
type ResponseError struct {
Status int `json:"status"`
Error Error `json:"error"`
}

// Error ... エラー
// Error ... error
type Error struct {
Message string `json:"message"`
}

// NewResponseError ... エラーレスポンスを取得する
// NewResponseError ... get error response
func NewResponseError(status int, message string) *ResponseError {
return &ResponseError{
Status: status,
Expand Down
4 changes: 2 additions & 2 deletions src/domain/model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package model

import "github.com/abyssparanoia/rapid-go/src/infrastructure/entity"

// User ... ユーザーモデル
// User ... user model
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Sex string `json:"sex"`
}

// NewUserFromEntity ... entityからdomain modelへの変換をかねる
// NewUserFromEntity ... convert from entity to model
func NewUserFromEntity(e *entity.User) *User {
return &User{
ID: e.ID,
Expand Down
2 changes: 1 addition & 1 deletion src/domain/repository/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/abyssparanoia/rapid-go/src/infrastructure/entity"
)

// User ... ユーザーレポジトリのinterface
// User ... user interface
type User interface {
Get(ctx context.Context, userID int64) (*entity.User, error)
}
6 changes: 3 additions & 3 deletions src/handler/api/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
validator "gopkg.in/go-playground/validator.v9"
)

// UserHandler ... ユーザーハンドラー
// UserHandler ... user handler
type UserHandler struct {
Svc service.User
}
Expand All @@ -23,7 +23,7 @@ type userHandlerGetResponse struct {
User *model.User `json:"user"`
}

// Get ... ユーザー情報を取得する
// Get ... get user
func (h *UserHandler) Get(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

Expand All @@ -49,7 +49,7 @@ func (h *UserHandler) Get(w http.ResponseWriter, r *http.Request) {
handler.RenderJSON(w, http.StatusOK, userHandlerGetResponse{User: user})
}

// NewUserHandler ... ユーザーハンドラーを取得する
// NewUserHandler ... get user handler
func NewUserHandler(Svc service.User) *UserHandler {
return &UserHandler{
Svc: Svc,
Expand Down
2 changes: 1 addition & 1 deletion src/handler/empty.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ package handler

import "net/http"

// Empty ... 空のハンドラ
// Empty ... empty handler
func Empty(w http.ResponseWriter, r *http.Request) {
}
8 changes: 4 additions & 4 deletions src/handler/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import (
"github.com/go-chi/chi"
)

// GetURLParam ... リクエストからURLParamを取得する
// GetURLParam ... get URL parameters from request
func GetURLParam(r *http.Request, key string) string {
return chi.URLParam(r, key)
}

// GetFormValue ... リクエストからFormValueを取得する
// GetFormValue ... get form values from request
func GetFormValue(r *http.Request, key string) string {
return r.FormValue(key)
}

// GetJSON ... リクエストからJSONを取得する
// GetJSON ... get json data from request
func GetJSON(r *http.Request, dst interface{}) error {
dec := json.NewDecoder(r.Body)
err := dec.Decode(dst)
Expand All @@ -32,7 +32,7 @@ func GetJSON(r *http.Request, dst interface{}) error {
return nil
}

// GetFormFile ... リクエストからファイルを取得する
// GetFormFile ... get file data from request
func GetFormFile(r *http.Request, key string) (multipart.File, *multipart.FileHeader, error) {
return r.FormFile(key)
}
2 changes: 1 addition & 1 deletion src/handler/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"net/http"
)

// Ping ... 生存確認
// Ping ... confirmation survival
func Ping(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("pongpong"))
Expand Down
12 changes: 6 additions & 6 deletions src/handler/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"golang.org/x/text/transform"
)

// HandleError ... 一番典型的なエラーハンドリング
// HandleError ... handle for error
func HandleError(ctx context.Context, w http.ResponseWriter, msg string, err error) {
code, ok := errcode.Get(err)
if !ok {
Expand All @@ -42,31 +42,31 @@ func HandleError(ctx context.Context, w http.ResponseWriter, msg string, err err
}
}

// RenderSuccess ... 成功レスポンスをレンダリングする
// RenderSuccess ... render for success
func RenderSuccess(w http.ResponseWriter) {
r := render.New()
r.JSON(w, http.StatusOK, model.NewResponseOK(http.StatusOK))
}

// RenderError ... エラーレスポンスをレンダリングする
// RenderError ... render for error
func RenderError(w http.ResponseWriter, status int, msg string) {
r := render.New()
r.JSON(w, status, model.NewResponseError(status, msg))
}

// RenderJSON ... JSONをレンダリングする
// RenderJSON ... render json
func RenderJSON(w http.ResponseWriter, status int, v interface{}) {
r := render.New(render.Options{IndentJSON: true})
r.JSON(w, status, v)
}

// RenderHTML ... HTMLをレンダリングする
// RenderHTML ... render html
func RenderHTML(w http.ResponseWriter, status int, name string, values interface{}) {
r := render.New()
r.HTML(w, status, name, values)
}

// RenderCSV ... CSVをレンダリングする
// RenderCSV ... render csv
func RenderCSV(w http.ResponseWriter, name string, data [][]string) {
w.Header().Set("Content-Type", "text/csv")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment;filename=%s.csv", name))
Expand Down
Loading

0 comments on commit c2bc45d

Please sign in to comment.