2

I am building a Book API in Golang using Gin and GORM. I have successfully implemented the Create, get and delete parts of the API but the Update is resulting in 500 Internal Server Error. I am trying to for a Update functionality which only updates the specific tags provided in the body(example given below). Any help or guidance is greatly appreciated.

GO Logs

[31m2022/05/09 14:08:00 [Recovery] 2022/05/09 - 14:08:00 panic recovered:
PATCH /books/2 HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 66
Content-Type: text/plain;charset=UTF-8
Origin: chrome-extension://ihgpcfpkpmdcghlnaofdmjkoemnlijdi
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: none
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36


reflect: call of reflect.Value.SetString on uint Value
C:/Program Files/Go/src/reflect/value.go:221 (0xc7bb04)
        flag.mustBe: panic(&ValueError{methodName(), f.kind()})
C:/Program Files/Go/src/reflect/value.go:1747 (0xc7ba3e)
        Value.SetString: v.mustBe(String)
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/schema/field.go:771 (0x10defb7)
        (*Field).setupValuerAndSetter.func11: field.ReflectValueOf(ctx, value).SetString(data)
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:144 (0x115b68e)
        ConvertToAssignments.func2: field.Set(stmt.Context, stmt.ReflectValue, value)
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:275 (0x11534f9)
        ConvertToAssignments: assignValue(field, value)
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/callbacks/update.go:73 (0x115ac9e)
        Update.func1: if set := ConvertToAssignments(db.Statement); len(set) != 0 {
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/callbacks.go:130 (0x10ebe14)
        (*processor).Execute: f(db)
C:/Users/NK086843/go/pkg/mod/gorm.io/[email protected]/finisher_api.go:372 (0x10f4e8d)
        (*DB).Updates: return tx.callbacks.Update().Execute(tx)
C:/New folder/golang/github.com/shashank-kakarla/BookAPI/controllers/books.go:101 (0x1167007)
        UpdateBook: models.DB.Model(&book).Updates(input)
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x10917e1)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:99 (0x10917c7)
        CustomRecoveryWithWriter.func1: c.Next()
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x10908c6)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:241 (0x1090885)
        LoggerWithConfig.func1: c.Next()
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:168 (0x1086689)
        (*Context).Next: c.handlers[c.index](c)
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:555 (0x108666f)
        (*Engine).handleHTTPRequest: c.Next()
C:/Users/NK086843/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:511 (0x1086112)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
C:/Program Files/Go/src/net/http/server.go:2867 (0xe76e29)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
C:/Program Files/Go/src/net/http/server.go:1932 (0xe721ac)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
C:/Program Files/Go/src/runtime/asm_amd64.s:1371 (0xc3d900)
        goexit: BYTE    $0x90   // NOP
←[0m
[GIN] 2022/05/09 - 14:08:00 |←[97;41m 500 ←[0m|     19.7185ms |       127.0.0.1 |←[97;42m PATCH   ←[0m "/books/2"

GO Models

func UpdateBook(c *gin.Context) {
    // Get model if exist
    var book models.Book
    if err := models.DB.Where("id = ?", c.Param("id")).First(&book).Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Record not found!"})
        return
    }

    // Validate input
    var input UpdateBookInput
    if err := c.ShouldBindJSON(&input); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    models.DB.Model(&book).Updates(input)

    c.JSON(http.StatusOK, gin.H{"data": book})
}

UpdateBookInput Struct

type UpdateBookInput struct {
    Title  string `json:"title"`
    Author string `json:"author"`
}

main.go

func main() {

    router := gin.Default()

    models.ConnectDatabase()

    router.GET("/books", controllers.FetchBooks)
    router.GET("/books/:id", controllers.FindBookByID)
    router.GET("/books/title/:title", controllers.FindBookByTitle)
    router.GET("/books/author/:author", controllers.FindBookByAuthor)

    router.POST("/books", controllers.CreateBook)

    router.PATCH("/books/:id", controllers.UpdateBook)

    router.DELETE("/books/:id", controllers.RemoveBook)

    router.Run()
}

Request URL and Body URL

PATCH http://127.0.0.1:8080/books/2

BODY

{
    "title": "Breaking Dawn",
}

Schema/Model

package models

type Book struct {
    ID     uint   `json:"id" gorm:"primary_key"`
    Title  string `json:"title"`
    Author string `json:"author"`
}

5
  • I have also tried using maps instead of struct in the Updates param but when only few columns are given in the JSON, the rest of columns are updated as empty once the Update Query is processed in GORM. Commented May 9, 2022 at 19:19
  • @TheFool I have added the schema for the DB in the question above. Commented May 9, 2022 at 20:25
  • what does the UpdateBookInput struct look like? Commented May 9, 2022 at 22:16
  • @TheFool I created the table with GORM and I am using mysql database. Commented May 10, 2022 at 8:42
  • @EminLaletovic I added the struct structure in the question above. Commented May 10, 2022 at 8:44

2 Answers 2

1

I suppose the JSON data contains an ID field which is of type string, because the only uint field is ID here. Either gorm is behaving weird with Updates or its something like this.

Make sure the input is clean.

0

Instead of passing the UpdateBookInput object directly, convert it to a models.Book object.

3
  • I get an InvalidConversion Error when I do that. Commented May 10, 2022 at 8:48
  • Is to you create a function that convert the object to the correct one
    – Jictyvoo
    Commented May 11, 2022 at 19:58
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented May 12, 2022 at 1:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.