title: Golang multipart file form request
body: <p>I'm writing an API client against Mapbox, uploading a batch of svg images to a custom map. The api they provide for this is documented with an example cUrl call that works fine:</p>
  <p><code>curl -F images=@include/mapbox/sprites_dark/aubergine_selected.svg &quot;https://api.mapbox.com/styles/v1/&lt;my_company&gt;/&lt;my_style_id&gt;/sprite?access_token=$MAPBOX_API_KEY&quot; --trace-ascii /dev/stdout</code></p>
  <p>When attemting to do the same from golang I quickly came across that the multiform library is very limited, and wrote some code to make the request as similar to the cUrl request mentioned above.</p>
  <pre class="lang-golang prettyprint-override"><code>func createMultipartFormData(fileMap map[string]string) (bytes.Buffer, *multipart.Writer) {
      var b bytes.Buffer
      var err error
      w := multipart.NewWriter(&amp;b)
      var fw io.Writer
      for fileName, filePath := range fileMap {
  
          h := make(textproto.MIMEHeader)
          h.Set(&quot;Content-Disposition&quot;,
              fmt.Sprintf(`form-data; name=&quot;%s&quot;; filename=&quot;%s&quot;`, &quot;images&quot;, fileName))
          h.Set(&quot;Content-Type&quot;, &quot;image/svg+xml&quot;)
  
          if fw, err = w.CreatePart(h); err != nil {
              fmt.Printf(&quot;Error creating form File %v, %v&quot;, fileName, err)
              continue
          }
  
          fileContents, err := ioutil.ReadFile(filePath)
          fileContents = bytes.ReplaceAll(fileContents, []byte(&quot;\n&quot;), []byte(&quot;.&quot;))
  
          blockSize := 64
          remainder := len(fileContents) % blockSize
          iterations := (len(fileContents) - remainder) / blockSize
  
          newBytes := []byte{}
          for i := 0; i &lt; iterations; i++ {
              start := i * blockSize
              end := i*blockSize + blockSize
              newBytes = append(newBytes, fileContents[start:end]...)
              newBytes = append(newBytes, []byte(&quot;\n&quot;)...)
          }
  
          if remainder &gt; 0 {
              newBytes = append(newBytes, fileContents[iterations*blockSize:]...)
              newBytes = append(newBytes, []byte(&quot;\n&quot;)...)
          }
  
          if err != nil {
              fmt.Printf(&quot;Error reading svg file: %v: %v&quot;, filePath, err)
              continue
          }
  
          _, err = fw.Write(newBytes)
  
          if err != nil {
              log.Debugf(&quot;Could not write file to multipart: %v, %v&quot;, fileName, err)
              continue
          }
      }
  
      w.Close()
  
      return b, w
  }
  
  </code></pre>
  <p>Along with setting the headers in the actual request:</p>
  <pre class="lang-golang prettyprint-override"><code>    bytes, formWriter := createMultipartFormData(filesMap)
  
      req, err := http.NewRequest(&quot;Post&quot;, fmt.Sprintf(&quot;https://api.mapbox.com/styles/v1/%v/%v/sprite?access_token=%v&quot;, &quot;my_company&quot;, styleID, os.Getenv(&quot;MAPBOX_API_KEY&quot;)), &amp;bytes)
  
      if err != nil {
          return err
      }
  
      req.Header.Set(&quot;User-Agent&quot;, &quot;curl/7.64.1&quot;)
      req.Header.Set(&quot;Accept&quot;, &quot;*/*&quot;)
      req.Header.Set(&quot;Content-Length&quot;, fmt.Sprintf(&quot;%v&quot;, len(bytes.Bytes())))
      req.Header.Set(&quot;Content-Type&quot;, formWriter.FormDataContentType())
  
      byts, _ := httputil.DumpRequest(req, true)
      fmt.Println(string(byts))
  
      res, err := http.DefaultClient.Do(req)
  
  </code></pre>
  <p>Even want as far to limit the line length and replicate the encoding used by cUrl but so far no luck. Does anyone with experience know why this works from cUrl but not golang?</p>