feat: add redis control in artcle feature

This commit is contained in:
pahmiudahgede 2025-01-22 12:55:54 +07:00
parent ef95e3bfbe
commit ef94470eda
4 changed files with 142 additions and 42 deletions

View File

@ -3,12 +3,12 @@ package domain
import "time"
type Article struct {
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
Title string `gorm:"not null" json:"title"`
CoverImage string `gorm:"not null" json:"coverImage"`
Author string `gorm:"not null" json:"author"`
Heading string `gorm:"not null" json:"heading"`
Content string `gorm:"not null" json:"content"`
PublishedAt time.Time `gorm:"not null" json:"publishedAt"`
UpdatedAt time.Time `gorm:"not null" json:"updatedAt"`
ID string `gorm:"primaryKey;type:uuid;default:uuid_generate_v4();unique;not null" json:"id"`
Title string `gorm:"not null" json:"title"`
CoverImage string `gorm:"not null" json:"coverImage"`
Author string `gorm:"not null" json:"author"`
Heading string `gorm:"not null" json:"heading"`
Content string `gorm:"not null" json:"content"`
PublishedAt time.Time `gorm:"default:current_timestamp" json:"createdAt"`
UpdatedAt time.Time `gorm:"default:current_timestamp" json:"updatedAt"`
}

View File

@ -13,13 +13,12 @@ func CreateArticle(c *fiber.Ctx) error {
if err := c.BodyParser(&articleRequest); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
fiber.StatusBadRequest,
"Invalid input",
"Input tidak valid",
nil,
))
}
if err := articleRequest.ValidatePostArticle(); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
fiber.StatusBadRequest,
err.Error(),
@ -31,7 +30,7 @@ func CreateArticle(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
fiber.StatusInternalServerError,
"Failed to create article",
"Gagal membuat artikel",
nil,
))
}
@ -52,7 +51,7 @@ func CreateArticle(c *fiber.Ctx) error {
return c.Status(fiber.StatusCreated).JSON(utils.FormatResponse(
fiber.StatusCreated,
"Article created successfully",
"Artikel berhasil dibuat",
response,
))
}
@ -63,7 +62,7 @@ func GetArticles(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
fiber.StatusInternalServerError,
"Failed to fetch articles",
"Gagal mengambil artikel",
nil,
))
}
@ -71,14 +70,13 @@ func GetArticles(c *fiber.Ctx) error {
if len(articles) == 0 {
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
fiber.StatusOK,
"Articles fetched successfully but data is empty",
"Artikel berhasil diambil tetapi data kosong",
[]dto.FormattedResponse{},
))
}
var formattedArticles []dto.FormattedResponse
for _, article := range articles {
article.PublishedAtFormatted = utils.FormatDateToIndonesianFormat(article.PublishedAt)
article.UpdatedAtFormatted = utils.FormatDateToIndonesianFormat(article.UpdatedAt)
@ -96,19 +94,20 @@ func GetArticles(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
fiber.StatusOK,
"Articles fetched successfully",
"Artikel berhasil diambil",
formattedArticles,
))
}
func GetArticleByID(c *fiber.Ctx) error {
id := c.Params("id")
article, err := services.GetArticleByID(id)
if err != nil {
return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse(
fiber.StatusNotFound,
"Article not found",
"Artikel tidak ditemukan",
nil,
))
}
@ -129,7 +128,7 @@ func GetArticleByID(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
fiber.StatusOK,
"Article fetched successfully",
"Artikel berhasil diambil",
response,
))
}
@ -142,13 +141,12 @@ func UpdateArticle(c *fiber.Ctx) error {
if err := c.BodyParser(&articleUpdateRequest); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
fiber.StatusBadRequest,
"Invalid input",
"Input tidak valid",
nil,
))
}
if err := articleUpdateRequest.ValidateUpdateArticle(); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(utils.FormatResponse(
fiber.StatusBadRequest,
err.Error(),
@ -158,9 +156,17 @@ func UpdateArticle(c *fiber.Ctx) error {
updatedArticle, err := services.UpdateArticle(id, &articleUpdateRequest)
if err != nil {
if err.Error() == "record not found" {
return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse(
fiber.StatusNotFound,
"id article tidak diketahui",
nil,
))
}
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
fiber.StatusInternalServerError,
"Failed to update article",
"Gagal memperbarui artikel",
nil,
))
}
@ -181,7 +187,7 @@ func UpdateArticle(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
fiber.StatusOK,
"Article updated successfully",
"Artikel berhasil diperbarui",
response,
))
}
@ -191,16 +197,24 @@ func DeleteArticle(c *fiber.Ctx) error {
err := services.DeleteArticle(id)
if err != nil {
if err.Error() == "record not found" {
return c.Status(fiber.StatusNotFound).JSON(utils.FormatResponse(
fiber.StatusNotFound,
"id article tidak diketahui",
nil,
))
}
return c.Status(fiber.StatusInternalServerError).JSON(utils.FormatResponse(
fiber.StatusInternalServerError,
"Failed to delete article",
"Gagal menghapus artikel",
nil,
))
}
return c.Status(fiber.StatusOK).JSON(utils.FormatResponse(
fiber.StatusOK,
"Article deleted successfully",
"Artikel berhasil dihapus",
nil,
))
}

View File

@ -1,49 +1,87 @@
package repositories
import (
"encoding/json"
"time"
"github.com/pahmiudahgede/senggoldong/config"
"github.com/pahmiudahgede/senggoldong/domain"
"golang.org/x/net/context"
)
var ctx = context.Background()
func CreateArticle(article *domain.Article) error {
err := config.DB.Create(article).Error
if err != nil {
return err
}
config.RedisClient.Del(ctx, "articles")
return nil
}
func GetArticles() ([]domain.Article, error) {
var articles []domain.Article
err := config.DB.Find(&articles).Error
cachedArticles, err := config.RedisClient.Get(ctx, "articles").Result()
if err == nil {
err := json.Unmarshal([]byte(cachedArticles), &articles)
if err != nil {
return nil, err
}
return articles, nil
}
err = config.DB.Find(&articles).Error
if err != nil {
return nil, err
}
articlesJSON, _ := json.Marshal(articles)
config.RedisClient.Set(ctx, "articles", articlesJSON, 10*time.Minute)
return articles, nil
}
func GetArticleByID(id string) (domain.Article, error) {
var article domain.Article
err := config.DB.Where("id = ?", id).First(&article).Error
cachedArticle, err := config.RedisClient.Get(ctx, "article:"+id).Result()
if err == nil {
err := json.Unmarshal([]byte(cachedArticle), &article)
if err != nil {
return article, err
}
return article, nil
}
err = config.DB.Where("id = ?", id).First(&article).Error
if err != nil {
return article, err
}
articleJSON, _ := json.Marshal(article)
config.RedisClient.Set(ctx, "article:"+id, articleJSON, 10*time.Minute)
return article, nil
}
func UpdateArticle(article *domain.Article) error {
err := config.DB.Save(article).Error
if err != nil {
return err
}
config.RedisClient.Del(ctx, "article:"+article.ID)
config.RedisClient.Del(ctx, "articles")
return nil
}
func DeleteArticle(id string) error {
var article domain.Article
err := config.DB.Where("id = ?", id).First(&article).Error
if err != nil {
return err
@ -53,5 +91,9 @@ func DeleteArticle(id string) error {
if err != nil {
return err
}
config.RedisClient.Del(ctx, "article:"+id)
config.RedisClient.Del(ctx, "articles")
return nil
}
}

View File

@ -1,22 +1,25 @@
package services
import (
"context"
"encoding/json"
"time"
"github.com/pahmiudahgede/senggoldong/config"
"github.com/pahmiudahgede/senggoldong/domain"
"github.com/pahmiudahgede/senggoldong/dto"
"github.com/pahmiudahgede/senggoldong/internal/repositories"
)
var ctx = context.Background()
func CreateArticle(articleRequest *dto.ArticleRequest) (dto.ArticleResponse, error) {
article := domain.Article{
Title: articleRequest.Title,
CoverImage: articleRequest.CoverImage,
Author: articleRequest.Author,
Heading: articleRequest.Heading,
Content: articleRequest.Content,
PublishedAt: time.Now(),
UpdatedAt: time.Now(),
Title: articleRequest.Title,
CoverImage: articleRequest.CoverImage,
Author: articleRequest.Author,
Heading: articleRequest.Heading,
Content: articleRequest.Content,
}
err := repositories.CreateArticle(&article)
@ -24,6 +27,8 @@ func CreateArticle(articleRequest *dto.ArticleRequest) (dto.ArticleResponse, err
return dto.ArticleResponse{}, err
}
config.RedisClient.Del(ctx, "articles")
articleResponse := dto.ArticleResponse{
ID: article.ID,
Title: article.Title,
@ -39,12 +44,22 @@ func CreateArticle(articleRequest *dto.ArticleRequest) (dto.ArticleResponse, err
}
func GetArticles() ([]dto.ArticleResponse, error) {
var response []dto.ArticleResponse
cachedArticles, err := config.RedisClient.Get(ctx, "articles").Result()
if err == nil {
err := json.Unmarshal([]byte(cachedArticles), &response)
if err != nil {
return nil, err
}
return response, nil
}
articles, err := repositories.GetArticles()
if err != nil {
return nil, err
}
var response []dto.ArticleResponse
for _, article := range articles {
response = append(response, dto.ArticleResponse{
ID: article.ID,
@ -57,15 +72,30 @@ func GetArticles() ([]dto.ArticleResponse, error) {
UpdatedAt: article.UpdatedAt,
})
}
articlesJSON, _ := json.Marshal(response)
config.RedisClient.Set(ctx, "articles", articlesJSON, 10*time.Minute)
return response, nil
}
func GetArticleByID(id string) (dto.ArticleResponse, error) {
cachedArticle, err := config.RedisClient.Get(ctx, "article:"+id).Result()
if err == nil {
var article dto.ArticleResponse
err := json.Unmarshal([]byte(cachedArticle), &article)
if err != nil {
return article, err
}
return article, nil
}
article, err := repositories.GetArticleByID(id)
if err != nil {
return dto.ArticleResponse{}, err
}
return dto.ArticleResponse{
articleResponse := dto.ArticleResponse{
ID: article.ID,
Title: article.Title,
CoverImage: article.CoverImage,
@ -74,7 +104,12 @@ func GetArticleByID(id string) (dto.ArticleResponse, error) {
Content: article.Content,
PublishedAt: article.PublishedAt,
UpdatedAt: article.UpdatedAt,
}, nil
}
articleJSON, _ := json.Marshal(articleResponse)
config.RedisClient.Set(ctx, "article:"+id, articleJSON, 10*time.Minute)
return articleResponse, nil
}
func UpdateArticle(id string, articleUpdateRequest *dto.ArticleUpdateRequest) (*dto.ArticleResponse, error) {
@ -96,7 +131,10 @@ func UpdateArticle(id string, articleUpdateRequest *dto.ArticleUpdateRequest) (*
return nil, err
}
return &dto.ArticleResponse{
config.RedisClient.Del(ctx, "article:"+id)
config.RedisClient.Del(ctx, "articles")
updatedArticleResponse := dto.ArticleResponse{
ID: article.ID,
Title: article.Title,
CoverImage: article.CoverImage,
@ -105,7 +143,9 @@ func UpdateArticle(id string, articleUpdateRequest *dto.ArticleUpdateRequest) (*
Content: article.Content,
PublishedAt: article.PublishedAt,
UpdatedAt: article.UpdatedAt,
}, nil
}
return &updatedArticleResponse, nil
}
func DeleteArticle(id string) error {
@ -114,5 +154,9 @@ func DeleteArticle(id string) error {
if err != nil {
return err
}
config.RedisClient.Del(ctx, "article:"+id)
config.RedisClient.Del(ctx, "articles")
return nil
}
}