How to download files using Swag golang library?

1.8k views Asked by At

I am trying to make a REST API using gin-gonic in golang, which takes some path parameters from a GET request & downloads that file.

That works correctly by curl command. However, when I add swagger UI documentation, then if the downloaded file is text or image, it is just displayed in that webpage, but I can't see any download option. Further the browser hangs if I enter the path of a video file.

Also, the MIME type of the file to be downloaded is determined correctly from gin-gonic. But, to download the file via swagger UI interface, I am using hardcoded @Accept & @Produce swagger UI comment annotations. It should ideally determine that MIME type automatically.

Currently the response type is listed as drop down, where I get various options. I need that to automatically detect correct MIME type & display a download button if possible

My code for the GET request is:

// DownloadObject godoc
// @Summary Download object
// @Description Download object
// @Produce application/json
// @Produce text/plain
// @Produce application/octet-stream
// @Produce video/mp4
// @Produce image/png
// @Produce image/jpeg
// @Produce image/gif
// @Param rootPath path string true "Root Path"
// @Param filePath path string true "File Path"
// @Header 200 {string} Token "qwerty"
// @Router /transfer/{rootPath}/{filePath} [get]
func DownloadObject(c *gin.Context) {

    // Get rootPath & filePath from GET request
    rootPath := c.Param("rootPath")
    filePath := c.Param("filePath")


    // Some code to get an io.Reader object "download"

    _, err = io.Copy(c.Writer, download)
    if err != nil {
        c.Status(http.StatusInternalServerError)
        log.Print(err)
        return
    }

    err = download.Close()
    if err != nil {
        c.Status(http.StatusInternalServerError)
        log.Print(err)
        return
    }
    
    c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%", filePath))
    c.Writer.Header().Add("Content-Type", c.GetHeader("Content-Type"))
    // Object download completed & closed successfully

}

Am I missing something here?

1

There are 1 answers

0
xarantolus On BEST ANSWER

You're adding headers after the file has been received by the browser, move them before io.Copy for them to have an effect. Also you have a wrong formatting verb (just %) in the fmt.Sprintf call, use %q:

func DownloadObject(c *gin.Context) {

    // Get rootPath & filePath from GET request
    rootPath := c.Param("rootPath")
    filePath := c.Param("filePath")

    // ...

    // Add headers to the response
    c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filePath))
    c.Writer.Header().Add("Content-Type", c.GetHeader("Content-Type"))


    _, err = io.Copy(c.Writer, download)
    if err != nil {
        c.Status(http.StatusInternalServerError)
        log.Print(err)
        return
    }

    err = download.Close()
    if err != nil {
        c.Status(http.StatusInternalServerError)
        log.Print(err)
        return
    }
    
}