Skip to content

Commit

Permalink
Merge pull request #127 from yoshihiro-shu/refactor/gorilla/router
Browse files Browse the repository at this point in the history
add: new api handler
  • Loading branch information
yoshihiro-shu authored Jan 20, 2024
2 parents ef40ace + 800f384 commit 5380753
Show file tree
Hide file tree
Showing 20 changed files with 333 additions and 254 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go-testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_dispatch:
pull_request:
paths:
- "backend/**"
- "src/**"

permissions: read-all

Expand Down
30 changes: 22 additions & 8 deletions src/application/usecase/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ import (
type ArticleUseCase interface {
Create(title, content string, userId, categoryId int) (*model.Article, error)
FindByID(id int) (*model.Article, error)
GetArticles(articles *[]model.Article, limit, offset int) error
GetArticles(articles *[]model.Article, limit, offset, currentPage int) error
GetPager(currentPage, offset int) (*pager.Pager, error)
Update(id int, title, content string) (*model.Article, error)
Delete(id int) error
}

type articleUseCase struct {
articleRepo repository.ArticleRepository
cacheArticleRepo repository.ArticleCacheRepository
articleRepo repository.ArticleRepository
cacheArticleRepo repository.ArticleCacheRepository
cacheArticlesRepo repository.ArticlesCacheRepository
}

func NewArticleUseCase(articleRepo repository.ArticleRepository, cacheArticleRepo repository.ArticleCacheRepository) ArticleUseCase {
func NewArticleUseCase(articleRepo repository.ArticleRepository, cacheArticleRepo repository.ArticleCacheRepository, cacheArticlesRepo repository.ArticlesCacheRepository) ArticleUseCase {
return &articleUseCase{
articleRepo: articleRepo,
cacheArticleRepo: cacheArticleRepo,
articleRepo: articleRepo,
cacheArticleRepo: cacheArticleRepo,
cacheArticlesRepo: cacheArticlesRepo,
}
}

Expand Down Expand Up @@ -61,8 +63,20 @@ func (au *articleUseCase) FindByID(id int) (*model.Article, error) {
return &article, nil
}

func (au *articleUseCase) GetArticles(articles *[]model.Article, limit, offset int) error {
return au.articleRepo.GetArticles(articles, limit, offset)
func (au *articleUseCase) GetArticles(articles *[]model.Article, limit, offset, currentPage int) error {
if err := au.cacheArticlesRepo.GetLastest(articles, currentPage); err == nil {
return nil
}
err := au.articleRepo.GetArticles(articles, limit, offset)
if err != nil {
return err
}

if err := au.cacheArticlesRepo.SetLastest(articles, currentPage); err != nil {
// logのみを出力するエラーハンドリングに変えたい。
return err
}
return nil
}

func (au *articleUseCase) GetPager(currentPage, offset int) (*pager.Pager, error) {
Expand Down
3 changes: 2 additions & 1 deletion src/application/usecase/articles.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
)

type ArticlesUseCase interface {
// Get(articles *[]model.Article, limit, offset, currentPage int) error
GetPager(currentPage, offset int) (*pager.Pager, error)
GetArticlesByCategory(articles *[]model.Article, slug string) error
GetArticlesByTag(articles *[]model.Article, slug string) error
GetPager(currentPage, offset int) (*pager.Pager, error)
}

type articlesUseCase struct {
Expand Down
5 changes: 1 addition & 4 deletions src/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ func main() {
defer db.Close()

auth.Init(conf.AccessToken, conf.RefreshToken)
s := server.New(conf, logger, db, cache)

s.SetRouters()

s := server.New(conf, logger, db.Master, db.Reprica, cache)
s.Start()
}
27 changes: 14 additions & 13 deletions src/interfaces/api/handler/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/yoshihiro-shu/tech-blog-backend/src/application/usecase"
"github.com/yoshihiro-shu/tech-blog-backend/src/domain/model"
"github.com/yoshihiro-shu/tech-blog-backend/src/interfaces/api/request"
"github.com/yoshihiro-shu/tech-blog-backend/src/internal/logger"
"gorm.io/gorm"
)

Expand All @@ -20,7 +21,7 @@ type ArticleHandler interface {
type articleHandler struct {
articleUseCase usecase.ArticleUseCase
articlesUseCase usecase.ArticlesUseCase
C *request.Context
logger logger.Logger
}

// ArticleHandler godoc
Expand All @@ -37,18 +38,18 @@ func (ah *articleHandler) Get(w http.ResponseWriter, r *http.Request) error {
strId := vars["id"]
id, err := strconv.Atoi(strId)
if err != nil {
return ah.C.JSON(w, http.StatusInternalServerError, err.Error())
return request.JSON(w, http.StatusInternalServerError, err.Error())
}

article, err := ah.articleUseCase.FindByID(id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return ah.C.JSON(w, http.StatusNotFound, err.Error())
return request.JSON(w, http.StatusNotFound, err.Error())
}
return ah.C.JSON(w, http.StatusInternalServerError, err.Error())
return request.JSON(w, http.StatusInternalServerError, err.Error())
}

return ah.C.JSON(w, http.StatusOK, article)
return request.JSON(w, http.StatusOK, article)
}

type responseGetArticlesByCategory struct {
Expand All @@ -72,12 +73,12 @@ func (ah *articleHandler) GetArticlesByCategory(w http.ResponseWriter, r *http.R
err := ah.articlesUseCase.GetArticlesByCategory(&res.Articles, slug)
if err != nil {
if err == gorm.ErrRecordNotFound {
ah.C.Logger.Warn("err no articles at latest Articles Handler")
return ah.C.JSON(w, http.StatusNotFound, err)
ah.logger.Warn("err no articles at latest Articles Handler")
return request.JSON(w, http.StatusNotFound, err)
}
}

return ah.C.JSON(w, http.StatusOK, res)
return request.JSON(w, http.StatusOK, res)
}

type responseGetArticlesByTag struct {
Expand All @@ -101,18 +102,18 @@ func (ah *articleHandler) GetArticlesByTag(w http.ResponseWriter, r *http.Reques
err := ah.articlesUseCase.GetArticlesByTag(&res.Articles, slug)
if err != nil {
if err == gorm.ErrRecordNotFound {
ah.C.Logger.Warn("err no articles at latest Articles Handler")
return ah.C.JSON(w, http.StatusNotFound, err)
ah.logger.Warn("err no articles at latest Articles Handler")
return request.JSON(w, http.StatusNotFound, err)
}
}

return ah.C.JSON(w, http.StatusOK, res)
return request.JSON(w, http.StatusOK, res)
}

func NewArticleHandler(articleUseCase usecase.ArticleUseCase, articlesUseCase usecase.ArticlesUseCase, c *request.Context) ArticleHandler {
func NewArticleHandler(articleUseCase usecase.ArticleUseCase, articlesUseCase usecase.ArticlesUseCase, logger logger.Logger) ArticleHandler {
return &articleHandler{
articleUseCase: articleUseCase,
articlesUseCase: articlesUseCase,
C: c,
logger: logger,
}
}
27 changes: 6 additions & 21 deletions src/interfaces/api/handler/lastest_articles.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/gorilla/mux"
"github.com/yoshihiro-shu/tech-blog-backend/src/application/usecase"
"github.com/yoshihiro-shu/tech-blog-backend/src/domain/model"
"github.com/yoshihiro-shu/tech-blog-backend/src/infrastructure/persistence/cache"
"github.com/yoshihiro-shu/tech-blog-backend/src/interfaces/api/request"
"github.com/yoshihiro-shu/tech-blog-backend/src/internal/logger"
"github.com/yoshihiro-shu/tech-blog-backend/src/internal/pager"
Expand All @@ -20,7 +19,6 @@ type LatestArticlesHandler interface {
}

type latestArticlesHandler struct {
*request.Context
logger logger.Logger
articleUseCase usecase.ArticleUseCase
}
Expand All @@ -29,9 +27,8 @@ const (
numberOfArticlePerPageAtLatestAritcles = 5
)

func NewLatestArticlesHandler(articleUseCase usecase.ArticleUseCase, c *request.Context, l logger.Logger) LatestArticlesHandler {
func NewLatestArticlesHandler(articleUseCase usecase.ArticleUseCase, l logger.Logger) LatestArticlesHandler {
return &latestArticlesHandler{
Context: c,
logger: l,
articleUseCase: articleUseCase,
}
Expand Down Expand Up @@ -63,34 +60,22 @@ func (h latestArticlesHandler) Get(w http.ResponseWriter, r *http.Request) error

limit := numberOfArticlePerPageAtLatestAritcles
offset := limit * (currentPage - 1)

cacheKey := cache.GetLatestArticleListKey(currentPage)
err = h.Cache().GET(cacheKey, &res)
if err == nil {
return h.JSON(w, http.StatusOK, res)
}

err = h.articleUseCase.GetArticles(&res.Articles, limit, offset)
err = h.articleUseCase.GetArticles(&res.Articles, limit, offset, currentPage)
if err != nil {
if err == gorm.ErrRecordNotFound {
h.logger.Warn("err no articles at latest Articles Handler")
return h.JSON(w, http.StatusNotFound, err)
return request.JSON(w, http.StatusNotFound, err)
}
h.logger.Error("failed at get articles at latest articles.", zap.Error(err))
return h.Error(w, http.StatusInternalServerError, err)
return request.Error(w, http.StatusInternalServerError, err)
}

res.Pager, err = h.articleUseCase.GetPager(currentPage, limit)
if err != nil {
h.logger.Warn("failed at get pager at top page.", zap.Error(err))
return h.Error(w, http.StatusInternalServerError, err)
}

err = h.Cache().SET(cacheKey, res)
if err != nil {
h.logger.Error("failed at set cache redis at top page.", zap.Error(err))
return request.Error(w, http.StatusInternalServerError, err)
}

return h.JSON(w, http.StatusOK, res)
return request.JSON(w, http.StatusOK, res)

}
58 changes: 38 additions & 20 deletions src/interfaces/api/handler/top_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,30 @@ import (

"github.com/yoshihiro-shu/tech-blog-backend/src/application/usecase"
"github.com/yoshihiro-shu/tech-blog-backend/src/domain/model"
"github.com/yoshihiro-shu/tech-blog-backend/src/infrastructure/persistence/cache"
"github.com/yoshihiro-shu/tech-blog-backend/src/interfaces/api/request"
"github.com/yoshihiro-shu/tech-blog-backend/src/internal/logger"
"go.uber.org/zap"
"gorm.io/gorm"
)

type TopPageHandler interface {
Get(w http.ResponseWriter, r *http.Request) error
}

type topPageHandler struct {
*request.Context
logger logger.Logger
topPageUseCase usecase.TopPageUseCase
articleUseCase usecase.ArticleUseCase
}

const (
// 一ページあたりの記事数
numberOfArticlePerPage = 10
)

func NewTopPageHandler(topPageUseCase usecase.TopPageUseCase, c *request.Context, l logger.Logger) TopPageHandler {
func NewTopPageHandler(articleUseCase usecase.ArticleUseCase, l logger.Logger) LatestArticlesHandler {
return &topPageHandler{
Context: c,
logger: l,
topPageUseCase: topPageUseCase,
articleUseCase: articleUseCase,
}
}

Expand All @@ -47,28 +45,48 @@ type responseTopPage struct {
// @Failure 400 {object} request.JSONResponce{data=string}
// @Failure 500 {object} request.JSONResponce{data=string}
// @Router /api/top_page [get]
// func (h topPageHandler) Get(w http.ResponseWriter, r *http.Request) error {
// currentPage := 1
// var res responseTopPage

// resKey := cache.TopPageKey()
// err := h.Cache().GET(resKey, &res)
// if err == nil {
// return h.JSON(w, http.StatusOK, res)
// }

// // Number Of Articles Per 1 page
// limit := numberOfArticlePerPage
// offset := numberOfArticlePerPage * (currentPage - 1)
// err = h.topPageUseCase.GetArticles(&res.Article, limit, offset)
// if err != nil {
// h.logger.Warn("failed at get articles at top page.", zap.Error(err))
// return h.JSON(w, http.StatusInternalServerError, err.Error())
// }

// err = h.Cache().SET(resKey, res)
// if err != nil {
// h.logger.Error("failed at set cache redis at top page.", zap.Error(err))
// }
// return h.JSON(w, http.StatusOK, res)
// }

func (h topPageHandler) Get(w http.ResponseWriter, r *http.Request) error {
currentPage := 1
var res responseTopPage

resKey := cache.TopPageKey()
err := h.Cache().GET(resKey, &res)
if err == nil {
return h.JSON(w, http.StatusOK, res)
}

// Number Of Articles Per 1 page
limit := numberOfArticlePerPage
offset := numberOfArticlePerPage * (currentPage - 1)
err = h.topPageUseCase.GetArticles(&res.Article, limit, offset)
err := h.articleUseCase.GetArticles(&res.Article, limit, offset, currentPage)
if err != nil {
h.logger.Warn("failed at get articles at top page.", zap.Error(err))
return h.JSON(w, http.StatusInternalServerError, err.Error())
if err == gorm.ErrRecordNotFound {
h.logger.Warn("err no articles at latest Articles Handler")
return request.JSON(w, http.StatusNotFound, err)
}
h.logger.Error("failed at get articles at latest articles.", zap.Error(err))
return request.Error(w, http.StatusInternalServerError, err)
}

err = h.Cache().SET(resKey, res)
if err != nil {
h.logger.Error("failed at set cache redis at top page.", zap.Error(err))
}
return h.JSON(w, http.StatusOK, res)
return request.JSON(w, http.StatusOK, res)
}
21 changes: 21 additions & 0 deletions src/interfaces/api/request/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,24 @@ func (c Context) Error(w http.ResponseWriter, status int, err error) error {
}
return nil
}

func Error(w http.ResponseWriter, status int, err error) error {
res := errorResponse{
Status: status,
Err: err.Error(),
}

b, err := json.Marshal(res)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return nil
}

w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(status)
_, err = w.Write(b)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return nil
}
22 changes: 22 additions & 0 deletions src/interfaces/api/request/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,25 @@ func (c Context) JSON(w http.ResponseWriter, status int, data interface{}) error

return nil
}

func JSON(w http.ResponseWriter, status int, data interface{}) error {
res := JSONResponce{
Status: status,
Data: data,
}

b, err := json.Marshal(res)
if err != nil {
// c.Logger.Error("failed at convert response to json.", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return nil
}

w.WriteHeader(status)
_, _ = w.Write(b)
// if err != nil {
// c.Logger.Error("failed at write response.", zap.Error(err))
// }

return nil
}
Loading

0 comments on commit 5380753

Please sign in to comment.