Search code examples
goziphttp-postmultipartform-data

Send zip file as form-data in POST request


I am trying to send a zip file in POST request body as form-data in GO. So, it is supposed to be in a key-value format. I am able to achieve the same while sending an unzipped file. Here is the snippet,

buf := new(bytes.Buffer)
multiPartWriter := multipart.NewWriter(buf)
part, err := multiPartWriter.CreateFormFile("File", fileName)

However, when it comes to zipping it, I am able to find this,

zipWriter := zip.NewWriter(buf)
zipFile, err := zipWriter.Create(fileName)

Unlike multipart.Writer, in case of zip.Writer I can't find any option to create form file in a key-value fashion.

How can I achieve this for zip as well?

Code snippet[updated],

    func SendPostRequest(url string, content []byte, fileName string, 
     doZip bool)(*http.Response, error) {
    
        buf := new(bytes.Buffer)
        multiPartWriter := multipart.NewWriter(buf)
        part, _ := multiPartWriter.CreateFormFile("File", fileName)
        
            if doZip {
                zipWriter := zip.NewWriter(part)
                zipFile, _ := zipWriter.Create(fileName)
                zipFile.Write(content)
                zipWriter.Close()
            } else {
                part.Write(content)
                multiPartWriter.Close()
                
            }
            request, _ := http.NewRequest(http.MethodPost, url, buf)
        
            request.Header.Add(constants.Header_content_type_key, multiPartWriter.FormDataContentType())
        
            client := &http.Client{}
            response, err := client.Do(request)
        return client.Do(request)
     }

Solution

  • As a solution to this one - I am doing a zip of the content byte slice only, when it comes to zipping. Rest are common for both zipped/non-zipped approach. Here are the code snippets,

    func sendPostRequest(url string, content []byte, projectId string, fileName string, fileType string, doZip bool) (*http.Response, error) {
    
        buf := new(bytes.Buffer)
        writer := multipart.NewWriter(buf)
    
        part, err := writer.CreateFormFile("File", fileName)
        if err != nil {
            return nil, errors.New("Invocation of *multipart.Writer.CreateFormFile() failed: " + err.Error())
        }
    
        content, err = ZipBytes(fileName, content, doZip)
        if err != nil {
            return nil, err
        }
    
        _, err = part.Write(content)
        if err != nil {
            return nil, errors.New("Invocation of io.Writer.Write() failed: " + err.Error())
        }
    
        if err = writer.Close(); err != nil {
            return nil, errors.New("Failed to close *multipart.Writer: " + err.Error())
        }
    
        request, err := http.NewRequest(http.MethodPost, url, buf)
        if err != nil {
            return nil, errors.New("Failed to create request for Validation API multipart file uploading: " + err.Error())
        }
    
        request.Header.Add(constants.Header_content_type_key, writer.FormDataContentType())
        request.Header.Add(constants.Project_Id_header_str, projectId)
        request.Header.Add(constants.File_type_header_str, fileType)
    
        if doZip {
            request.Header.Add(constants.IsZipped_header_str, "true")
        } else {
            request.Header.Add(constants.IsZipped_header_str, "false")
        }
    
        client := &http.Client{}
        response, err := client.Do(request)
    
        if err != nil {
            return nil, errors.New("Failed to invoke Validation API: " + err.Error())
    
        } else if !strings.Contains(strconv.Itoa(response.StatusCode), "20") {
            respMap, _ := processValidationResponse(response)
            message := fmt.Sprintf("Failed to invoke Validation API with HTTP %s : %s", strconv.Itoa(response.StatusCode), respMap["message"])
            return nil, errors.New(message)
        }
    
        return response, nil
    }
    
    func ZipBytes(fileName string, content []byte, doZip bool) ([]byte, error) {
    
        if doZip {
    
            log.Println("Zipped file will be sent for validation")
            buf := new(bytes.Buffer)
            zipWriter := zip.NewWriter(buf)
    
            zipFile, err := zipWriter.Create(fileName)
    
            if err != nil {
                return nil, errors.New("Zip file creation failed: " + err.Error())
            }
    
            _, err = zipFile.Write(content)
            if err != nil {
                return nil, errors.New("Writing to zip file failed: " + err.Error())
            }
    
            if err = zipWriter.Close(); err != nil {
                return nil, errors.New("Failed to close zip writer: " + err.Error())
            }
    
            return buf.Bytes(), nil
    
        } else {
    
            log.Println("Normal file will be sent for validation")
            return content, nil
    
        }
    }