Skip to content

Commit

Permalink
Add: health check api
Browse files Browse the repository at this point in the history
  • Loading branch information
naohito-T committed May 5, 2024
1 parent d26bce6 commit 5ff53b8
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 113 deletions.
1 change: 0 additions & 1 deletion backend/configs/constructor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const (
// Description: APIエンドポイントの詳細な説明です。ここでは操作の詳細や動作についての追加情報を提供します。
// Tags: このAPI操作に関連付けられたタグのリストです。これにより、APIドキュメント内で類似の操作をグループ化することができます。


// huma.Register(app, huma.Operation{
// OperationID: "health",
// Method: http.MethodGet,
Expand Down
2 changes: 1 addition & 1 deletion backend/configs/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const (
// /api/v1/health
Health path = "/health"
// /api/v1/urls
GetShortURL path = "/urls/:shortUrl"
GetShortURL path = "/urls/:id"
// /api/v1/urls
CreateShortURL path = "/urls"
)
2 changes: 1 addition & 1 deletion backend/domain/shorturl.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

type ShortURL struct {
ID string `json:"id"`
OriginalURL string `json:"original"`
OriginalURL string `json:"original_url"`
CreatedAt string `json:"created_at"`
}

Expand Down
2 changes: 1 addition & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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/aws/smithy-go v1.20.2
github.com/danielgtaylor/huma/v2 v2.15.0
github.com/go-playground/validator/v10 v10.19.0
github.com/kelseyhightower/envconfig v1.4.0
Expand All @@ -28,7 +29,6 @@ require (
github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
Expand Down
2 changes: 0 additions & 2 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2M
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/danielgtaylor/huma/v2 v2.15.0 h1:26c3hxNT+0xNc8qDLPXNko48qyi31RDFQdhi36gorRI=
github.com/danielgtaylor/huma/v2 v2.15.0/go.mod h1:OdHC/JliXtOrnvHLQTU5qV7WvYRQXwWY1tkl5rLXmuE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down
6 changes: 6 additions & 0 deletions backend/internal/rest/handler/shorturl.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ShortURLHandler struct {

// IShortURLHandler defines the interface for short URL handler operations.
type IShortURLHandler interface {
GetShortURLHandler(ctx context.Context, hashID string) (domain.ShortURL, error)
CreateShortURLHandler(ctx context.Context, originalURL string) (domain.ShortURL, error)
}

Expand All @@ -24,6 +25,11 @@ func NewShortURLHandler(c *container.GuestContainer) IShortURLHandler {
}
}

func (s *ShortURLHandler) GetShortURLHandler(ctx context.Context, hashID string) (domain.ShortURL, error) {
slog.NewLogger().Info("GetShortURLHandler: %v", hashID)
return s.container.URLUsecase.GetByShortURL(ctx, hashID)
}

func (s *ShortURLHandler) CreateShortURLHandler(ctx context.Context, originalURL string) (domain.ShortURL, error) {
slog.NewLogger().Info("CreateShortURLHandler: %v", originalURL)
return s.container.URLUsecase.CreateShortURL(ctx, originalURL)
Expand Down
157 changes: 56 additions & 101 deletions backend/internal/rest/router/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,128 +2,60 @@ package router

import (
"context"
"fmt"
"net/http"

"github.com/danielgtaylor/huma/v2"
"github.com/naohito-T/tinyurl/backend/configs"
"github.com/naohito-T/tinyurl/backend/domain"
"github.com/naohito-T/tinyurl/backend/internal/infrastructures/slog"
"github.com/naohito-T/tinyurl/backend/internal/rest/container"
"github.com/naohito-T/tinyurl/backend/internal/rest/handler"
)

// huma.Register(app, huma.Operation{
// OperationID: "omittable",
// Method: http.MethodPost,
// Path: "/omittable",
// Summary: "Omittable / nullable example",
// }, func(ctx context.Context, input *struct {
// Body *struct {
// Name OmittableNullable[string] `json:"name,omitempty" maxLength:"10"`
// }
// }) (*MyResponse, error) {
// resp := &MyResponse{}
// if input.Body == nil {
// resp.Body.Message = "Body was not sent"
// } else if !input.Body.Name.Sent {
// resp.Body.Message = "Name was omitted from the request"
// } else if input.Body.Name.Null {
// resp.Body.Message = "Name was set to null"
// } else {
// resp.Body.Message = "Name was set to: " + input.Body.Name.Value
// }
// return resp, nil
// })

type FilterOrQuery struct {
FilterID int64 `query:"filter_id" doc:"filter_id and query are mutually exclusive"`
Query string `query:"query" doc:"filter_id and query are mutually exclusive"`
type HealthCheckQuery struct {
CheckDB bool `query:"q" doc:"Optional database check parameter"`
}

func (f *FilterOrQuery) Resolve(ctx huma.Context) []error {
if f.FilterID != 0 && f.Query != "" {
return []error{&huma.ErrorDetail{
Message: "Cannot pass both filter_id and query at the same time",
Location: "query",
Value: fmt.Sprintf("filter_id:%d query:%s", f.FilterID, f.Query),
}}
type HealthCheckResponse struct {
Body struct {
Message string `json:"message"`
}
return nil
}

// type HealthCheckParams struct {
// CheckDB string `json:"check_db"`
// }
type GetTinyURLQuery struct {
ID string `path:"id" required:"true"`
}

// GreetingOutput represents the greeting operation response.
type CreateTinyURLBody struct {
type GetTinyURLResponse struct {
Body struct {
URL string `json:"url" example:"http://example.com" doc:"URL to shorten"`
ID string `json:"id" required:"true"`
OriginalURL string `json:"original_url" required:"true"`
CreatedAt string `json:"created_at" required:"true"`
}
}

type HealthCheckQuery struct {
type CreateTinyURLBody struct {
Body struct {
Message string `json:"message,omitempty" example:"Hello, world!" doc:"Greeting message"`
URL string `json:"url" required:"true" example:"http://example.com" doc:"URL to shorten"`
}
}

// type HealthCheckResponse struct {
// Body struct {
// Message string `json:"message,omitempty" example:"Hello, world!" doc:"Greeting message"`
// }
// }

// HealthCheckParams はヘルスチェックのリクエストパラメータを定義します。
type HealthCheckParams struct {
CheckDB *string `query:"check_db" doc:"Optional database check parameter"`
}

// HealthCheckResponse はヘルスチェックのレスポンスを定義します。
type HealthCheckResponse struct {
Message string `json:"message"`
type CreateTinyURLResponse struct {
Body struct {
ID string `json:"id"`
}
}

// type OmittableNullable[T any] struct {
// Sent bool
// Null bool
// Value T
// }

// UnmarshalJSON unmarshals this value from JSON input.
// func (o *OmittableNullable[T]) UnmarshalJSON(b []byte) error {
// if len(b) > 0 {
// o.Sent = true
// if bytes.Equal(b, []byte("null")) {
// o.Null = true
// return nil
// }
// return json.Unmarshal(b, &o.Value)
// }
// return nil
// }

// Schema returns a schema representing this value on the wire.
// It returns the schema of the contained type.
// func (o OmittableNullable[T]) Schema(r huma.Registry) *huma.Schema {
// return r.Schema(reflect.TypeOf(o.Value), true, "")
// }

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

// 今日の課題
// 1. tinyulrのAPIを作成する
// 1. tinyulrのAPIを作成する(できそう)
// 2. テストを書く
// 3. ドキュメントを書く

// https://tinyurl.com/app/api/url/create"
// NewRouter これもシングルトンにした場合の例が気になる
func NewPublicRouter(app huma.API) {
h := handler.NewShortURLHandler(container.NewGuestContainer())

// これ見ていつか修正する https://aws.amazon.com/jp/builders-library/implementing-health-checks/
huma.Register(app, huma.Operation{
OperationID: "health",
Method: http.MethodGet,
Expand All @@ -132,14 +64,38 @@ func NewPublicRouter(app huma.API) {
Description: "Check the health of the service.",
Tags: []string{"Public"},
}, func(_ context.Context, input *struct {
FilterOrQuery
}) (*struct{}, error) {
fmt.Printf("Got filter_id:%d query:%s\n", input.FilterID, input.Query)
return nil, nil
HealthCheckQuery
}) (*HealthCheckResponse, error) {
slog.NewLogger().Info("Health Check: %v", input.CheckDB)
return &HealthCheckResponse{
Body: struct {
Message string `json:"message"`
}{
Message: "ok",
},
}, nil
})

// オリジナルのURLは必須
// ここではすぐにhandlerへ渡す
huma.Register(app, huma.Operation{
OperationID: "tinyurl",
Method: http.MethodGet,
Path: configs.GetShortURL,
Summary: "Get a original URL",
Description: "Get a original URL.",
Tags: []string{"Public"},
}, func(ctx context.Context, query *struct {
GetTinyURLQuery
}) (*GetTinyURLResponse, error) {
resp := &GetTinyURLResponse{}
shortURL, err := h.GetShortURLHandler(ctx, query.ID)
if err != nil {
return nil, err
}
resp.Body.ID = shortURL.ID
resp.Body.OriginalURL = shortURL.OriginalURL
resp.Body.CreatedAt = shortURL.CreatedAt
return resp, nil
})

huma.Register(app, huma.Operation{
OperationID: "tinyurl",
Expand All @@ -148,14 +104,13 @@ func NewPublicRouter(app huma.API) {
Summary: "Create a short URL",
Description: "Create a short URL.",
Tags: []string{"Public"},
}, func(ctx context.Context, body *CreateTinyURLBody) (*domain.ShortURL, error) {
}, func(ctx context.Context, body *CreateTinyURLBody) (*CreateTinyURLResponse, error) {
resp := &CreateTinyURLResponse{}
shortURL, err := h.CreateShortURLHandler(ctx, body.Body.URL)
if err != nil {
return nil, err
}
return &shortURL, nil
resp.Body.ID = shortURL.ID
return resp, nil
})

// e.GET(Router.GetShortURL, hello)
// e.POST(Router.CreateShortURL, hello)
}
9 changes: 3 additions & 6 deletions backend/internal/usecase/shorturl.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,9 @@ func NewURLUsecase(u IShortURLRepo) *ShortURLUsecase {
}
}

func (u *ShortURLUsecase) GetByShortURL(ctx context.Context, hashURL string) domain.ShortURL {
shortURL, err := u.shortURLRepo.Get(ctx, hashURL)
if err != nil {
panic(err)
}
return shortURL
func (u *ShortURLUsecase) GetByShortURL(ctx context.Context, hashID string) (domain.ShortURL, error) {
slog.NewLogger().Info("GetByShortURL: %v", hashID)
return u.shortURLRepo.Get(ctx, hashID)
}

func (u *ShortURLUsecase) CreateShortURL(ctx context.Context, originalURL string) (domain.ShortURL, error) {
Expand Down

0 comments on commit 5ff53b8

Please sign in to comment.