gomicroservices

how to write a function to send http request with a nullable body in go


in my app i want to repeatedly send http request for communication between our microservices. so i want to globally define a function for sending http requests.

package httputil
func SendRequest(method string, url string, body *bytes.Buffer) (*http.Response, error) {

    // Create client
    client := &http.Client{}
    var httpResponse *http.Response

    // Create request
    req, err := http.NewRequest(method, url, body)
    if err != nil {
        return httpResponse, err
    }

    // Fetch Request
    httpResponse, err = client.Do(req)
    if err != nil {
        return httpResponse, err
    }
    defer httpResponse.Body.Close()

    return httpResponse, nil
}
func DecodeResponseBody(httpResponse *http.Response) ([]byte, error) {
    body, err := io.ReadAll(httpResponse.Body)
    if err != nil {
        return nil, err
    }
    // Check if the response status is not OK
    if httpResponse.StatusCode != http.StatusOK {
        //return response, fmt.Errorf("received non-OK response status: %s, body: %s", resp.Status, string(body))
        return nil, errors.New(string(body))
    }
    return body, nil
}

then in my services i invoke this function like this

    package service
    //Fetch Request
    httpResponse, err := httputil.SendRequest(http.MethodDelete, url, nil)
    if err != nil {
        return response, err
    }

    var response string
    //Read Response
    responseBody, err := httputil.DecodeResponseBody(httpResponse)
    if err != nil {
        return response, err
    }
    defer httpResponse.Body.Close()
    // Decode the response body into the response variable
    if err := json.Unmarshal(responseBody, &response); err != nil {
        // return response, fmt.Errorf("error decoding response: %v, body: %s", err, string(body))
        return response, fmt.Errorf("%v", err)
    }

as shown in the example i may have to pass a nil body in some http requests. but when i pass a nil body my code panics, please give me a solution


Solution

  • See Why is my nil value not nil.

    Fix by declaring SendRequest as:

    func SendRequest(method string, url string, body io.Reader) (*http.Response, error) {
        ...
    }
    

    This ensures that a nil argument in SendRequest's caller is passed as a nil io.Reader to the HTTP client.

    In the original code, a nil *bytes.Buffer is passed to the HTTP client and the *bytes.Buffer methods panic because the method receiver is nil.

    Example: https://go.dev/play/p/6UjKFf5wMj_y