Golang: Read from an io.ReadWriter without losing its content

Here is the scenario: You have some code that runs before your controller action. It reads the body of the request, does something with it and then continues.

Easy right?

var bodyBytes []byte
if body != nil {
bodyBytes, _ = ioutil.ReadAll(c.Request.Body)
}
bodyString := string(bodyBytes)

Then surprisingly your tests fail. The reason is when the controller reads from the Request.Body, which is an io.ReadCloser type, there is no content.

When you read from io.ReadCloser it drains it. Once you read from it, the content is gone. You can’t read from it a second time.

Think about the io.ReadCloser as a tap: You can get the water, but once it’s out it’s out.

Luckily there is a way around it. You can set the io.ReadCloser back using the content you just read:

// Read the content
var bodyBytes []byte
if c.Request.Body != nil {
bodyBytes, _ = ioutil.ReadAll(c.Request.Body)
}
// Restore the io.ReadCloser to its original state
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
// Use the content
bodyString := string(bodyBytes)

It’s not hard when you find the solution.

I’ve seen a lot of people on the internet were surprised by this behaviour and they had a similar issue. I hope this helps.

Aldo "xoen" Giambelluca

Written by

Software Engineer. Son, brother, grandchild, dog lover. I believe in readable, clean code that speak easy to you (with a slightly italian accent)

Aldo "xoen" Giambelluca

Written by

Software Engineer. Son, brother, grandchild, dog lover. I believe in readable, clean code that speak easy to you (with a slightly italian accent)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store