Search code examples
gogo-gorm

How to handle with GORM a JSON that corresponds to a database schema?


I am writing a backend API that sends to the frontend some JSON data from a database (handled by GORM). The frontend, after some modifications to the content of the fields, sends me back the data also as JSON.

Below is a mock-up of the code

package main

import (
    "encoding/json"
    "fmt"

    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type User struct {
    ID     uint
    Name   string
    Card   Card
    CardID uint
}

type Card struct {
    ID     uint
    Number string
}

func main() {
    // initialize the database
    db, _ := gorm.Open(sqlite.Open("mytest.sqlite"), &gorm.Config{})
    db.Debug()
    db.AutoMigrate(&User{}, &Card{})
    // create two cards
    db.Create(&Card{
        Number: "42",
    })
    db.Create(&Card{
        Number: "100",
    })
    // find one of them
    var myCard Card
    db.Where(map[string]interface{}{"number": "42"}).First(&myCard)
    // create a user with that card
    db.Create(&User{
        Name: "john",
        Card: myCard,
    })
    // find that user
    var myUser User
    db.Preload("Card").Where(map[string]interface{}{"name": "john"}).Last(&myUser)
    // this is then marshalled to JSON, and sent to a frontend.
    // on that frontend there are some changes and I get back the JSON
    // this is simulated below:
    // the card itself changed
    myUser.Card.ID = "2"
    myUser.Card.ID = "100"
    // the name of the user changed
    myUser.Name = "mary"
    output, _ := json.Marshal(myUser)
    fmt.Print(string(output))
    // Now output holds the JSON string
}

// output
// {"ID":12,"Name":"mary","Card":{"ID":2,"Number":"100"},"CardID":1}

My question is about how to handle output so that it can be written back into the database.

I do not really know GORM (or ORM for that matter) and I do not understand how to handle the fact that:

  • the ID of the card was changed
  • the Name of the user changed

In particular, I do not understand whether GORM will just "know" that the attached card is now different (and corresponds to a card in the database). I believe that the fact that Name changed is not a problem (because the ID is the same)


Solution

  • You can decode the JSON body into a user struct, and then do an update with it.

    func patchUser(w http.ResponseWriter, r *http.Request) {
        // get the id from the url i.e. /users/1
        // you need to use a framework or implement this yourself
        id := getId(r.URL)
    
        // decode the body into a new user
        patch := User{}
        json.NewDecoder(r.Body).Decode(&patch)
        
        // patch the user at the given id
        db.Model(User{}).Where("id = ?", id).Updates(patch)
    }
    

    You can find docs about updates here: https://gorm.io/docs/update.html