I hope I can explain this right. I'm trying to make an HTTP post request that contains binary data (a file). This is for DeepStack image processing. In Python I have the following working:
image_data = open(file,"rb").read()
try:
response = requests.post("http://deepstack.local:82/v1/vision/detection",files={"image":image_data},timeout=15).json()
In Go, I started with the basic example from here: https://golangtutorial.dev/tips/http-post-json-go/
Modifying this a bit for my use, the relevant lines are:
data, err := ioutil.ReadFile(tempPath + file.Name())
if err != nil {
log.Print(err)
}
httpposturl := "http://deepstack.local:82/v1/vision/custom/combined"
fmt.Println("HTTP JSON POST URL:", httpposturl)
var jsonData = []byte(`{"image": ` + data + `}`)
request, error := http.NewRequest("POST", httpposturl, bytes.NewBuffer(jsonData))
request.Header.Set("Content-Type", "application/json; charset=UTF-8")
This results in an error:
invalid operation: `{"image": ` + data (mismatched types untyped string and []byte)`
the "data" variable at this point is []uint8 ([]byte). I realize, at a high level, what is wrong. I'm trying to join two data types that are not the same. That's about it though. I've tried a bunch of stuff that I'm pretty sure anyone familiar with Go would immediately realize was wrong (declaring jsonData as a byte, converting data to a string, using os.Open instead of ioutil.ReadFile, etc.). I'm just kind of stumbling around blind though. I can't find an example that doesn't use a plain string as the JSON data.
I would appreciate any thoughts.
--- ANSWER ---
I'm marking Dietrich Epp's answer as accepted, because he gave me what I asked for. However, RedBlue in the comments gave me what I actually needed. Thank you both. The code below is modified just a bit from this answer: https://stackoverflow.com/a/56696333/2707357
Change the url variable to your DeepStack server, and the file name to one that actually exists, and the response body should return the necessary information.
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
)
func createMultipartFormData(fieldName, fileName string) (bytes.Buffer, *multipart.Writer) {
var b bytes.Buffer
var err error
w := multipart.NewWriter(&b)
var fw io.Writer
file := mustOpen(fileName)
if fw, err = w.CreateFormFile(fieldName, file.Name()); err != nil {
fmt.Println("Error: ", err)
}
if _, err = io.Copy(fw, file); err != nil {
fmt.Println("Error: ", err)
}
w.Close()
return b, w
}
func mustOpen(f string) *os.File {
r, err := os.Open(f)
if err != nil {
pwd, _ := os.Getwd()
fmt.Println("PWD: ", pwd)
panic(err)
}
return r
}
func main() {
url := "http://deepstack.local:82/v1/vision/custom/combined"
b, w := createMultipartFormData("image", "C:\\go_sort\\temp\\person.jpg")
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return
}
// Don't forget to set the content type, this will contain the boundary.
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{}
response, error := client.Do(req)
if err != nil {
panic(error)
}
defer response.Body.Close()
fmt.Println("response Status:", response.Status)
fmt.Println("response Headers:", response.Header)
body, _ := ioutil.ReadAll(response.Body)
fmt.Println("response Body:", string(body))
}