-2

I made a simple post API to store articles in database using Gorm And Go Gin.

problem with API showing when I tried to post the category name instead of the category id because the struct declaring it as int32 type

I made a simple function to getting the id of the category instead of the name but i don't know how to inject it within the incoming request

The article model

package models

import (
    "gorm.io/gorm"
)

type News struct {
    Id          int    `gorm:"primary_key;auto_increment;not_null" json:"id"`
    Category    int32  `gorm:"category" json:"category" binding:"required"`
    CountryID   int32  `gorm:"country_id" json:"country_id" binding:"required"`
    LangID      int32  `gorm:"lang_id" json:"lang_id" binding:"required"`
    SourceId    int32  `gorm:"source_id" json:"source_id" binding:"required"`
    HashtagId   int32  `gorm:"hashtag_id" json:"hashtag_id" binding:"required"`
    Title       string `gorm:"title" json:"title" binding:"required"`
    Content     string `gorm:"content" json:"content" binding:"required"`
    Description string `gorm:"description" json:"description" binding:"required"`
    Summery     string `gorm:"summery" json:"summery" binding:"required"`
    ImageUrl    string `gorm:"image_url" json:"image_url" binding:"required"`
    SourceUrl   string `gorm:"source_url" json:"source_url" binding:"required"`
    Author      string `gorm:"author" json:"author" `
}

func CreateArticle(db *gorm.DB, article *News) (err error) {
    err = db.Create(article).Error
    if err != nil {
        return err
    }
    return nil
}

Category Model

package models

import "gorm.io/gorm"

type Category struct {
    Id     int32  `gorm:"primary_key;auto_increment;not_null" json:"id"`
    Name   string `gorm:"category_name" json:"category" binding:"required"`
    Parent int32  `gorm:"parent" json:"parent"`
}

func GetCategoryByName(db *gorm.DB, category *Category, name string) (err error) {
    err = db.Where("LOWER(category_name) Like LOWER(?)", "%"+name+"%").First(category).Error
    if err != nil {
        return err
    }
    return nil
}

News Controller which implement the models

package controllers

import (
    "errors"
    "net/http"

    "github.com/fouad82/news-app-go/models"
    "github.com/gin-gonic/gin"
    "github.com/gin-gonic/gin/binding"
    "gorm.io/gorm"
)

type NewsRepo struct {
    db *gorm.DB
}

func NewArticle() *NewsRepo {
    db := models.InitDb()
    return &NewsRepo{db: db}
}

// CreateArticle Create Article
func (repository *NewsRepo) CreateArticle(c *gin.Context) {

    var Category models.Category
    if err := c.ShouldBindBodyWith(&Category, binding.JSON); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"status": "error", "error": &Category})
        return

    }
    err := models.GetCategoryByName(repository.db, &Category, Category.Name)
    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            c.AbortWithStatus(http.StatusNotFound)
            return
        }
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"status": "error", "error": err})
        return
    }
    var CategoryId = Category.Id
    var Article models.News
    Article.Category = CategoryId
    if err := c.ShouldBindBodyWith(&Article, binding.JSON); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"status": "error", "error": err})
        return

    }
    err = models.GetArticleByTitle(repository.db, &Article, Article.Title)
    if err == nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            c.AbortWithStatus(http.StatusNotFound)
            return
        }

        c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"status": "error", "error": "Title Created Before"})
        return
    }
    createArticle := models.CreateArticle(repository.db, &Article)
    if createArticle != nil {
        c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"status": "error", "error": createArticle})
        return
    }
    c.JSON(http.StatusOK, gin.H{"status": "ok", "result": "Article Created"})
}

in this line i tried to inject the int value within the article struct abut it still getting error that im passing string value not int and this because it still read from the request json not the injected parameter

var CategoryId = Category.Id
var Article models.News
Article.Category = CategoryId
Marco
  • 842
  • 6
  • 18
  • 42
  • 1
    I'm having a hard time parsing your question. Please can you explain more precisely what you're trying to do, and/or reformulate the question? – blackgreen Jul 28 '21 at 19:45
  • The incoming request is string and I need to make a db query to get the id before adding the article and then inject this id instead of the string – Marco Jul 28 '21 at 22:18
  • unclear. you should try to write one reproducible example. cat.ID is int32, article.catID is int32 so IDK. –  Aug 08 '21 at 22:30

1 Answers1

0

I believe the function you are using is out of request scope, so it's basically can not affect the gin.Context.

What I suggest is to copy the context in order to modify it with your changed data. Article.Category in specific.

...
    c.Copy
...

The other thing is about the function - it's evaluating itself - I would suggest to exclude it from CreateArticle function

createArticle := models.CreateArticle(repository.db, &Article)

What I also suggest is to return changed struct and work with it separately from request payload - probably you need to create another function for that:

   func (repository *NewsRepo) ChangedArticle(c *gin.Context)News{



    changedNews := News{
        Id:          0,
        Category:    0, // Here is where you change it
        CountryID:   0,
        LangID:      0,
        SourceId:    0,
        HashtagId:   0,
        Title:       "",
        Content:     "",
        Description: "",
        Summery:     "",
        ImageUrl:    "",
        SourceUrl:   "",
        Author:      "",
    }

        return changedNews

}

and than in your main function - just use it:

    ...
createArticle := models.ChangedArticle
    ...

I could miss some details, but I hope this top level explanation helps.