The Go language is one of my favorite programming languages. However, sometimes doing simple things can seem a bit harder than it should. However, most of the time, the problem is just to find out how to do things the easy way. While Go’s documention isn’t bad, the real key to finding out how to do things is often to look at the source code and the test suite.
I’m not yet super familiar with all the std lib packages, so when I wanted to test my Go web services, I wrote a few lines of code to create a multipart file upload function that was building the body from scratch. Once I was done messing with the various headers, boundary protocol etc.. I started testing some edge cases, I found some bugs in my code. Looking at Go’s packages, I realized that all the tools were already available for me to use. I was just lacking a good example. Walking through the test suite I finally figured out how to write a simple multipart file upload example with some extra query params.
Hopefully this example will be helpful to some of you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
All the work is done in the
newfileUploadRequest function and
mime/multipart package hides all the complexity of
creating a multipart request.
The key is to set a new
The writer will do all the work and will write directly to our body (which itself is a buffer of bytes).
We then create a part for the file form entry with the name of the file
param and the name of the file (that we extracted using the
We need to add the content of the file to the file part, we use the
io.Copy() to do so. In the first version of this article, I had used
Readall to read the content of the file (see code here).
However a few readers rightfully mentioned that I should instead copy
content from the file to the part instead of temporarily loading the content of
the file in memory. Here is an
even more optimized version using goroutine to stream the data, and
here is the full example using a pipe.
multipart.Writer takes care of setting the boundary and formating
the form data for us, nice isn’t it?!
Then for any extra params passed as a map of string keys to string
value, we use another function of the
Once again, the writer takes care of creating the right headers, and to add the passed value.
At this point, we just need to close our writer and use our body to create a new request.
One last thing before triggering our request, we need to set the header that contains the content type including the boundary being used. Once again, the Go lib has us covered:
As a reference, here is the generated body:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Golang might not be as high level as Ruby or Python, but it’s not too far off and it certainly comes with some great std libs. I know I recently caught myself writing a lot of small scripts in Go, something I used to do in Ruby. I think this is mainly due to the fact that Go is compiled, designed for concurrency, has great std libs and is quite easy to write.
Hopefully this code sample illustrates how easy Go can be and can also serve as a reference point if you are looking for a way to do multipart upload.