<commit_before>package api

import (
	"encoding/json"
	"net/http"
)

// Response is a raw response that wraps an HTTP response.
type Response struct {
	*http.Response
}

// DecodeJSON will decode the response body to a JSON structure. This
// will consume the response body, but will not close it. Close must
// still be called.
func (r *Response) DecodeJSON(out interface{}) error {
	dec := json.NewDecoder(r.Body)
	return dec.Decode(out)
}<commit_msg>api: Response can decode errors<commit_after>package api

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

// Response is a raw response that wraps an HTTP response.
type Response struct {
	*http.Response
}

// DecodeJSON will decode the response body to a JSON structure. This
// will consume the response body, but will not close it. Close must
// still be called.
func (r *Response) DecodeJSON(out interface{}) error {
	dec := json.NewDecoder(r.Body)
	return dec.Decode(out)
}

// Error returns an error response if there is one. If there is an error,
// this will fully consume the response body, but will not close it. The
// body must still be closed manually.
func (r *Response) Error() error {
	// 200 to 399 are okay status codes
	if r.StatusCode >= 200 && r.StatusCode < 400 {
		return nil
	}

	// We have an error. Let's copy the body into our own buffer first,
	// so that if we can't decode JSON, we can at least copy it raw.
	var bodyBuf bytes.Buffer
	if _, err := io.Copy(&bodyBuf, r.Body); err != nil {
		return err
	}

	// Decode the error response if we can. Note that we wrap the bodyBuf
	// in a bytes.Reader here so that the JSON decoder doesn't move the
	// read pointer for the original buffer.
	var resp ErrorResponse
	dec := json.NewDecoder(bytes.NewReader(bodyBuf.Bytes()))
	if err := dec.Decode(&resp); err != nil {
		// Ignore the decoding error and just drop the raw response
		return fmt.Errorf(
			"Error making API request. Code: %d. Raw Message:\n\n%s",
			r.StatusCode, bodyBuf.String())
	}

	var errBody bytes.Buffer
	errBody.WriteString(fmt.Sprintf(
		"Error making API request. Code: %d. Errors:\n\n", r.StatusCode))
	for _, err := range resp.Errors {
		errBody.WriteString(fmt.Sprintf("* %s", err))
	}

	return fmt.Errorf(errBody.String())
}

// ErrorResponse is the raw structure of errors when they're returned by the
// HTTP API.
type ErrorResponse struct {
	Errors []string
}
{'fraction_non_alphanumeric': 0.1078020134228188, 'fraction_numerical': 0.0050335570469798654, 'mean_word_length': 3.5170454545454546, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3166572', 'n_tokens_mistral': 759, 'n_tokens_neox': 727, 'n_words': 310}