based on the Google Drive API docs the proper way of uploading a file is:
curl -v -H 'Authorization: Bearer mytoken' -F 'metadata={"name": "test3.jpeg"};type=application/json' -F file=@jpeg_image.jpeg 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart'
Now, I need to perform the same request from golang code, but I am having a hard time translating this to golang, here is the code I am using after several attempts:
// fileBytes are of type []byte
buffer := &bytes.Buffer{}
multipartWriter := multipart.NewWriter(buffer)
multipartWriter.WriteField("metadata", "{\"name\": \"test3.jpef\"};type=application/json")
partHeader := textproto.MIMEHeader{}
partHeader.Add("Content-Type", "image/jpeg")
filePartWriter, _ := multipartWriter.CreatePart(partHeader)
io.Copy(filePartWriter, bytes.NewReader(fileBytes))
multipartWriter.Close()
googleDriveRequest, _ := http.NewRequest(http.MethodPost, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", buffer)
googleDriveRequest.Header.Add("Authorization", "Bearer "+accessToken)
googleDriveRequest.Header.Add("Content-Type", multipartWriter.FormDataContentType())
googleDriveAPIResponse, googleDriveAPIError := lib.HttpClient.Do(googleDriveRequest)
Using curl the request succeeds :
{
"kind": "drive#file",
"id": "1DwsbQGP3-QtS5p0iQqRtAjcCCsAfxzGD",
"name": "test3.jpeg",
"mimeType": "image/jpeg"
}
With Golang, I get a 400:
{\n \"error\": {\n \"errors\": [\n {\n \"domain\": \"global\",\n \"reason\": \"badContent\",\n \"message\": \"Unsupported content with type: image/jpeg \"\n }\n ],\n \"code\": 400,\n \"message\": \"Unsupported content with type: image/jpeg\"\n }\n}\n
I also tried with different values for partHeader.Add("Content-Type", "image/jpeg")
, I tried with application/x-www-form-urlencoded
as well, I also commented out this line, and let golang do the detection, but still getting the same error.
Any suggestions or ideas?
Regards,
The problem is in the JSON metadata that you send. Here is a sample code (use proper error checking) that will work,
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"net/textproto"
)
func main() {
accessToken := "YOUR-TOKEN"
client := http.Client{}
mediaData, _ := ioutil.ReadFile("test.png")
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// JSON Metadata (part-1)
jsonMetadata := textproto.MIMEHeader{}
metadata := `{"name": "test.png"}`
jsonMetadata.Set("Content-Type", "application/json")
part, _ := writer.CreatePart(jsonMetadata)
part.Write([]byte(metadata))
// Image bytes (part-2)
imageData := textproto.MIMEHeader{}
partAttach, _ := writer.CreatePart(imageData)
io.Copy(partAttach, bytes.NewReader(mediaData))
writer.Close()
// Request Content Type with boundary
contentType := fmt.Sprintf("multipart/related; boundary=%s", writer.Boundary())
// HTTP Request with auth and content type headers
req, _ := http.NewRequest(http.MethodPost, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart", bytes.NewReader(body.Bytes()))
req.Header.Add("Authorization", "Bearer "+accessToken)
req.Header.Add("Content-Type", contentType)
// Send request
resp, err := client.Do(req)
if err != nil {
log.Fatalf("failed to send request: %v", err)
}
defer resp.Body.Close()
content, _ := ioutil.ReadAll(resp.Body)
log.Printf("http status: %d", resp.StatusCode)
log.Printf("response: %s", string(content))
}
Reference: https://developers.google.com/drive/api/v3/manage-uploads?authuser=1#send_a_multipart_upload_request