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)