41

I am willing to create a sample http.Response instance in golang with a sample body string.

Problem is, its body property accepts ReadCloser instance. But as its a dummy response instance, I was wondering if there is some trick to set it easily without setting up all that stream read/close parts.

3
  • 3
    You can extend a simple string reader or something similar with a dummy Close method. Commented Nov 29, 2015 at 1:33
  • 6
    Which is done for you: ioutiil.NopCloser Commented Nov 29, 2015 at 2:04
  • Now you can use http.NoBody. Commented Jan 10, 2022 at 10:35

4 Answers 4

64

As suggested by Not_a_Golfer and JimB:

io.ReadCloser is an interface that is satisfied when a struct implements both the Read and the Close functions.

Fortunately, there is io.NopCloser, which takes a io.Reader and wraps it in the nopCloser struct, which implements both Read and Close. However, its Close function does nothing as implied from the name.

Here is an example:

package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    t := http.Response{
        Body: io.NopCloser(bytes.NewBufferString("Hello World")),
    }

    buff := bytes.NewBuffer(nil)
    t.Write(buff)

    fmt.Println(buff)
}

To play with the code, click here.

Sign up to request clarification or add additional context in comments.

Comments

29

Further to the top answer, I have found that in order for the response to be treated as the genuine article by clients, it needs to be more fully formed. For a normal (200) response, I do the following:

body := "Hello world"
t := &http.Response{
  Status:        "200 OK",
  StatusCode:    200,
  Proto:         "HTTP/1.1",
  ProtoMajor:    1,
  ProtoMinor:    1,
  Body:          ioutil.NopCloser(bytes.NewBufferString(body)),
  ContentLength: int64(len(body)),
  Request:       req,
  Header:        make(http.Header, 0),
}

Then you can, for example, add headers (with a 401 status code, to ask for authorisation, say). req is the http.Request for which you are generating the response.

Comments

3

This should work..

func main(){

    go serveHTTP(*port, *host)

    select {}
}

func serveHTTP(port int, host string) {

    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        requestHandler(w, r)
    })

    addr := fmt.Sprintf("%v:%d", host, port)
    server := &http.Server {
        Addr:           addr,
        Handler:        mux,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }

    err := server.ListenAndServe()
    log.Println(err.Error())
}

func requestHandler(w http.ResponseWriter, r *http.Request){
  fmt.Fprintf(w, `Success!`)
}

1 Comment

This is the simplest answer IMHO.
2

Yes, the ioutil.NopCloser is just what I needed!

Am trying to test a method that performs calls to the facebook API (via a helper function) for a social-connect endpoint, and I want to mock the facebook response coming from the helper function, so my solution is like follows:

Expected facebook response (converted to my own UserData struct) is:

UserData {
    ID:        facebookID,
    Email:     email,
    FirstName: firstName,
    LastName:  lastName,
}

So I create the expected response like this:

fbUserData, _ := json.Marshal(UserData{
    ID:        facebookID,
    Email:     email,
    FirstName: firstName,
    LastName:  lastName,
})
fbUserDataResponse := &http.Response{
    Body: ioutil.NopCloser(bytes.NewBufferString(string(fbUserData))),
}

Then I can mock the response for the method calling the facebook API like this:

s.fbGateway.EXPECT().ExecuteGetQuery(userUrl).Return(fbUserDataResponse, nil).Times(1)

The point here is that this is really about mocking any kind of functions that return *http.Response data (in my case I am calling the facebook API via a helper function that returns the http Response, as mentioned above).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.