When working with HTTP APIs that return large payloads, it’s a common practice to compress responses using Gzip to reduce bandwidth and latency.

In Go, the HTTP client automatically decompresses Gzip responses if you don’t explicitly set the Accept-Encoding: gzip header. This behavior is convenient for most scenarios. However, if you manually add the Accept-Encoding header, Go assumes you want to handle the decompression yourself.

Manually Handling Gzip Responses in Go

If you explicitly set the Accept-Encoding: gzip header, Go does not automatically decompress the response. You’ll need to handle it manually, like so:

client := &http.Client{}

req, err := http.NewRequest("GET", "http://httpbin.org/gzip", nil)
if err != nil {
	fmt.Printf("Error creating request: %s\n", err)
	return
}

req.Header.Add("Accept-Encoding", "gzip")

resp, err := client.Do(req)
if err != nil {
	fmt.Printf("Error making request: %s\n", err)
	return
}
defer resp.Body.Close()

if resp.Header.Get("Content-Encoding") == "gzip" {
  fmt.Println("Response is GZIP compressed. Decompressing...")

	gzipReader, err := gzip.NewReader(resp.Body)
	if err != nil {
		fmt.Printf("Error creating gzip reader: %s\n", err)
		return
	}
	defer gzipReader.Close()

	bodyBytes, err := io.ReadAll(gzipReader)
	if err != nil {
		fmt.Printf("Error reading decompressed response body: %s\n", err)
		return
	}

	fmt.Println("Decompressed Response Body:")
	fmt.Println(string(bodyBytes))

} else {
	fmt.Println("Response is not GZIP compressed. Reading directly...")

	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("Error reading response body: %s\n", err)
		return
	}

	fmt.Println("Response Body:")
	fmt.Println(string(bodyBytes))
}

Letting Go Handle Decompression Automatically

If you don’t set the Accept-Encoding header manually, Go will add it for you and take care of the decompression transparently. Here’s how that looks:

client := &http.Client{}

req, err := http.NewRequest("GET", "http://httpbin.org/gzip", nil)
if err != nil {
	fmt.Printf("Error creating request: %s\n", err)
	return
}

req.Header.Add("Accept-Encoding", "gzip")

resp, err := client.Do(req)
if err != nil {
	fmt.Printf("Error making request: %s\n", err)
	return
}
defer resp.Body.Close()

fmt.Println("Reading directly...")

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
	fmt.Printf("Error reading response body: %s\n", err)
	return
}

fmt.Println("Response Body:")
fmt.Println(string(bodyBytes))

Why Would You Handle Gzip Manually?

There are a few reasons why you might want to handle Gzip compression yourself:

  • Custom decompression logic (e.g., streaming decompression for large files)
  • Logging or inspecting raw response headers and body
  • Working with APIs that use non-standard encodings

In most cases, however, letting Go manage it for you is the simpler and safer option.