diff --git a/client.go b/client.go index 03aff7b..afd1557 100644 --- a/client.go +++ b/client.go @@ -61,6 +61,10 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) { // JSON // +// DoJSON, GetJSON, PostJSON, PutJSON, and DeleteJSON all set the appropriate +// JSON headers and decode the response body into the target. Pass nil as +// target to skip decoding — useful for endpoints that return no body (e.g. +// 204 No Content). func (c *Client) DoJSON(req *http.Request, target any) error { req.Header.Set("Content-Type", "application/json") @@ -84,7 +88,12 @@ func (c *Client) DoJSON(req *http.Request, target any) error { return fmt.Errorf("got %d code and response: %s", resp.StatusCode, string(body)) } - if err := json.NewDecoder(resp.Body).Decode(&target); err != nil { + if target == nil { + _, _ = io.Copy(io.Discard, resp.Body) + return nil + } + + if err := json.NewDecoder(resp.Body).Decode(target); err != nil { return fmt.Errorf("got %d code and failed to decode response body: %w", resp.StatusCode, err) } return nil diff --git a/client_test.go b/client_test.go index 0da6ff8..c6a3387 100644 --- a/client_test.go +++ b/client_test.go @@ -71,6 +71,19 @@ func TestClientDoJSON(t *testing.T) { assert.Equal(t, "joebob", user.Name) } +func TestClientDoJSONNilTarget204(t *testing.T) { + handler, client, cleanup := setup(t) + defer cleanup() + + handler.On("HandleWithHeaders", "DELETE", "/users/1", jsonHeaderMatcher, mock.Anything).Return(httpmock.Response{ + Status: http.StatusNoContent, + }) + + req, err := http.NewRequest("DELETE", "/users/1", nil) + require.NoError(t, err) + require.NoError(t, client.DoJSON(req, nil)) +} + type TestUser struct { ID int `json:"id,omitempty"` Name string `json:"name"`