How to show image in golang rest API response

4.4k Views Asked by At

In my application there is model of User with a field user image. I can upload user image into server but when I am trying to retrieve user data by user id I am not getting the image link as rest API response. The below is code for model and function--

type User struct {
    ID        uint32    `gorm:"primary_key;auto_increment" json:"id"`
    Nickname  string    `gorm:"size:255;not null;unique" json:"nickname"`
    Email     string    `gorm:"size:100;not null;unique" json:"email"`
    Password  string    `gorm:"size:100;not null;" json:"password,omitempty"`
    UserImage []byte    `gorm:"size:254;" json:"user_image"`
    CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
    UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
}


func (u *User) FindUserByID(db *gorm.DB, uid uint32) (*User, error) {
    err := db.Debug().Model(User{}).Select([]string{"id", "nickname", "email", "user_image"}).Where("id = ?", uid).Take(&u).Error
    if err != nil {
        return &User{}, err
    }
    if gorm.IsRecordNotFoundError(err) {
        return &User{}, errors.New("User Not Found")
    }
    return u, err
}

Controller for user image upload and to get user by ID:

func (server *Server) UploadFile(w http.ResponseWriter, r *http.Request) {
    file, handler, err := r.FormFile("user_image")
    fileName := r.FormValue("file_name")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    f, err := os.OpenFile("media/images/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        panic(err)
    }
    defer f.Close()
    _, _ = io.WriteString(w, "File "+fileName+" Uploaded successfully")
    _, _ = io.Copy(f, file)
}



func (server *Server) GetUser(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    uid, err := strconv.ParseUint(vars["id"], 10, 32)
    if err != nil {
        responses.ERROR(w, http.StatusBadRequest, err)
        return
    }
    user := models.User{}
    userGotten, err := user.FindUserByID(server.DB, uint32(uid))
    if err != nil {
        responses.ERROR(w, http.StatusBadRequest, err)
        return
    }
    responses.JSON(w, http.StatusOK, userGotten)
}

Routes to upload user image and get user by id:

s.Router.HandleFunc("/users/{id}/change_profile_image", middlewares.SetMiddlewareJSON(middlewares.SetMiddlewareAuthentication(s.UploadFile))).Methods("PUT")

s.Router.HandleFunc("/users/{id}", middlewares.SetMiddlewareJSON(s.GetUser)).Methods("GET")

File uploaded to path: media/images

Rest API response what I am getting:

{
    "id": 1,
    "nickname": "Shahid",
    "email": "[email protected]",
    "user_image": null,
    "created_at": "0001-01-01T00:00:00Z",
    "updated_at": "0001-01-01T00:00:00Z"
}

In the above I am getting user_image as null. But I want to return here the image link which I have already uploaded. Would you please help me regarding this issue?

Thanks in advance

1

There are 1 best solutions below

3
thrownew On

Check this article: https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang

Possible ways:

  1. Use FileServer to share files from disk. You need to add one new handler to provide images, and put into user_image field link to this handler. https://pkg.go.dev/net/http#FileServer Something like this (sorry for approximate code):
s.Router.Handle("/users/avatar", http.FileServer(http.Dir("/media/images"))

...

var user User

user.user_image = fmt.Sprintf("https://super.com/users/avatar/%d", user.ID)

  1. Another way is put image into user_image field as base64, but as far i understand you want to have URI there.

  2. You may return image without save it on disk like example with jpeg from here:

    func writeImage(w http.ResponseWriter, img *image.Image) {

        buffer := new(bytes.Buffer)
        if err := jpeg.Encode(buffer, *img, nil); err != nil {
            log.Println("unable to encode image.")
        }

        w.Header().Set("Content-Type", "image/jpeg")
        w.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes())))
        if _, err := w.Write(buffer.Bytes()); err != nil {
            log.Println("unable to write image.")
        }
    }