Skip to content

Commit

Permalink
Merge pull request #10 from naohito-T/feature/huma
Browse files Browse the repository at this point in the history
Feature/huma
  • Loading branch information
naohito-T authored Apr 29, 2024
2 parents 1dd4f5b + 161472e commit 6e2c48d
Show file tree
Hide file tree
Showing 13 changed files with 356 additions and 107 deletions.
2 changes: 1 addition & 1 deletion backend/.go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.21.0
1.21.9
16 changes: 6 additions & 10 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
# Backend

```sh
make dev

## memo
curl -X GET http://localhost:6500/openapi.yaml
```

- go vet
- コンパイラでは発見できないバグを見つける
- go testを走らせれば自動で実行される(Go 1.10から)
## API Specifies


要件

- go testを導入(これでgo vetもできる)
- go lintは非推奨
- staticcheckを導入(VSCodeではデフォルト)
see: <http://localhost:6500/docs>
73 changes: 67 additions & 6 deletions backend/cmd/api/main.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,81 @@
package main

import (
"fmt"
"net/http"

"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humaecho"
"github.com/danielgtaylor/huma/v2/humacli"
"github.com/labstack/echo/v4"
"github.com/naohito-T/tinyurl/backend/configs"
"github.com/naohito-T/tinyurl/backend/internal/rest/middleware"
"github.com/naohito-T/tinyurl/backend/internal/rest/router"
"github.com/spf13/cobra"
)

const (
defaultPort = ":6500"
)

// ここはCLIからの引数を受け取るための構造体
type Options struct {
Debug bool `doc:"Enable debug logging"`
Host string `doc:"Hostname to listen on."`
Port int `doc:"Port to listen on." short:"p" default:"8888"`
}

// publicにわける
// user(ログイン必須)
// private(管理者)

func main() {
// Echo instance
e := echo.New()
middleware.CustomMiddleware(e)
router.NewRouter(e)
// e.Startでエラーが発生した場合、Fatalでプログラムを終了する
e.Logger.Fatal(e.Start(defaultPort))
var api huma.API

cli := humacli.New(func(hooks humacli.Hooks, opts *Options) {
fmt.Printf("Options are debug:%v host:%v port%v\n", opts.Debug, opts.Host, opts.Port)

e := echo.New()
// configを初期化
configs.NewAppEnvironment()
config := huma.DefaultConfig(configs.OpenAPITitle, configs.OpenAPIVersion)
// Openapiのserver設定
config.Servers = []*huma.Server{
{URL: "http://localhost:6500/api/v1"},
}

config.Components.SecuritySchemes = map[string]*huma.SecurityScheme{
"bearer": {
Type: "http",
Scheme: "bearer",
BearerFormat: "JWT",
},
}
config.DocsPath = "/docs"
// ミドルウェアを適用(すべてのリクエストに対して)
middleware.CustomMiddleware(e)
// /api/v1/openapi.yaml
// これgroup化したやつをnewUserRouterに渡す必要かも
api = humaecho.NewWithGroup(e, e.Group("/api/v1"), config)
router.NewPublicRouter(api)

// 未定義のルート用のキャッチオールハンドラ
e.Any("/*", func(c echo.Context) error {
return c.JSON(http.StatusNotFound, map[string]string{"message": "route_not_found"})
})

hooks.OnStart(func() {
e.Logger.Fatal(e.Start(defaultPort))
})
})

cli.Root().AddCommand(&cobra.Command{
Use: "openapi",
Short: "Print the OpenAPI spec",
Run: func(_ *cobra.Command, _ []string) {
b, _ := api.OpenAPI().YAML()
fmt.Println(string(b))
},
})
cli.Run()
}
6 changes: 6 additions & 0 deletions backend/configs/constructor.go
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
package configs

const (
ApplicationPort = ":6500"
OpenAPITitle = "TinyURL"
OpenAPIVersion = "1.0.0"
)
24 changes: 24 additions & 0 deletions backend/configs/environment.go
Original file line number Diff line number Diff line change
@@ -1 +1,25 @@
package configs

import (
"fmt"
"sync"

"github.com/kelseyhightower/envconfig"
)

type AppEnvironment struct {
Stage string `default:"local"`
}

var newOnceLogger = sync.OnceValue(func() *AppEnvironment {
var ae AppEnvironment
if err := envconfig.Process("", &ae); err != nil {
panic(fmt.Sprintf("Failed to process environment config: %v", err))
}
return &ae
})

// SEE: https://pkg.go.dev/github.com/kelseyhightower/envconfig
func NewAppEnvironment() *AppEnvironment {
return newOnceLogger()
}
11 changes: 8 additions & 3 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.27.11
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.13
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.31.1
github.com/danielgtaylor/huma/v2 v2.14.0
github.com/go-playground/validator/v10 v10.19.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/labstack/echo/v4 v4.11.4
github.com/labstack/gommon v0.4.2
github.com/spf13/cobra v1.8.0
)

require (
Expand All @@ -30,15 +33,17 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
)
34 changes: 26 additions & 8 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/danielgtaylor/huma/v2 v2.14.0 h1:lRuhQQPZhePvJ4B/m4kfIUYfD8ZPy5BKq/oktLFmB50=
github.com/danielgtaylor/huma/v2 v2.14.0/go.mod h1:OdHC/JliXtOrnvHLQTU5qV7WvYRQXwWY1tkl5rLXmuE=
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/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
Expand All @@ -47,10 +54,16 @@ github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
Expand All @@ -64,21 +77,26 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
Expand Down
47 changes: 47 additions & 0 deletions backend/internal/rest/context/humaecho.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package context

// package humaecho

// import (
// "context"

// "github.com/danielgtaylor/huma/v2"
// "github.com/labstack/echo/v4"
// )

// // EchoHumaContext は huma.Context に echo.Context を追加します。
// type EchoHumaContext interface {
// // これは継承らしい
// huma.Context
// EchoContext() echo.Context
// }

// // echoContextImpl は EchoHumaContext の実装です。
// type echoContextImpl struct {
// humaCtx huma.Context
// echoCtx echo.Context
// }

// func (e *echoContextImpl) Operation() *huma.Operation {
// return e.humaCtx.Operation()
// }

// func (e *echoContextImpl) Context() context.Context {
// return e.humaCtx.Context()
// }

// // 以下、huma.Context の他のメソッドも同様に実装します。
// // ...

// // EchoContext は echo.Context を返します。
// func (e *echoContextImpl) EchoContext() echo.Context {
// return e.echoCtx
// }

// // NewEchoHumaContext は新しい EchoHumaContext を作成します。
// func NewEchoHumaContext(hCtx huma.Context, eCtx echo.Context) EchoHumaContext {
// return &echoContextImpl{
// humaCtx: hCtx, // huma.Context をセット
// echoCtx: eCtx, // echo.Context をセット
// }
// }
77 changes: 47 additions & 30 deletions backend/internal/rest/handler/health.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,49 @@
package handler

import (
"net/http"

"github.com/labstack/echo/v4"
"github.com/naohito-T/tinyurl/backend/domain/customerror"
)

// HealthCheckParams はヘルスチェックのパラメータを定義します
type HealthCheckParams struct {
// CheckDB *string `query:"check_db" validate:"required"`
CheckDB *string `query:"check_db"`
}

func HealthHandler(c echo.Context) error {
h := new(HealthCheckParams)
c.Logger().Error("Binding...")
if err := c.Bind(h); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
c.Logger().Error("Validating...")
if err := c.Validate(h); err != nil {
return &customerror.ValidationError{Message: "this is wrapped", Err: err}
}

if h.CheckDB != nil {
return c.JSON(http.StatusOK, map[string]string{"message": "check_db"})
}

return c.JSON(http.StatusOK, map[string]string{"message": "ok3"})
}
// import (
// "context"
// "net/http"

// "github.com/labstack/echo/v4"
// "github.com/naohito-T/tinyurl/backend/domain/customerror"
// )

// // HealthCheckParams はヘルスチェックのパラメータを定義します
// // type HealthCheckParams struct {
// // // CheckDB *string `query:"check_db" validate:"required"`
// // CheckDB *string `query:"check_db"`
// // }

// func HealthHandler(c echo.Context) error {
// h := new(HealthCheckParams)
// c.Logger().Error("Binding...")
// if err := c.Bind(h); err != nil {
// return echo.NewHTTPError(http.StatusBadRequest, err.Error())
// }
// c.Logger().Error("Validating...")
// if err := c.Validate(h); err != nil {
// return &customerror.ValidationError{Message: "this is wrapped", Err: err}
// }

// if h.CheckDB != nil {
// return c.JSON(http.StatusOK, map[string]string{"message": "check_db"})
// }

// return c.JSON(http.StatusOK, map[string]string{"message": "ok3"})
// }

// type HealthCheckParams struct {
// CheckDB *bool `json:"check_db"`
// }

// type HealthCheckParams2 struct {
// Message string `json:"message"`
// }

// // HealthHandler2 は、リクエストを受け取り、適切なレスポンスを返します。
// func HealthHandler2(ctx context.Context, params *HealthCheckParams) (*HealthCheckParams2, error) {
// if params.CheckDB != nil && *params.CheckDB {
// return &HealthCheckParams2{Message: "check_db"}, nil
// }
// return &HealthCheckParams2{Message: "ok3"}, nil
// }
5 changes: 5 additions & 0 deletions backend/internal/rest/middleware/error/error.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package error

// see: https://go.dev/play/p/TzZE1mdL63_1
// errors.Is()とerrors.As()は、
// errors.Is(err, target)
// ラップされたエラーでも、targetとなるエラーと一致するかどうか、値として判定したい時。
// errors.As(err, target)
// ラップされたエラーでも、targetとなるエラーに代入可能かどうか、型として判定したい時。

import (
"errors"
Expand Down
Loading

0 comments on commit 6e2c48d

Please sign in to comment.