Skip to content

feat: auto deduce content type when requesting data#49

Merged
wenchy merged 5 commits into
masterfrom
auto-deduce-content-type-when-requesting-data
Jul 16, 2026
Merged

feat: auto deduce content type when requesting data#49
wenchy merged 5 commits into
masterfrom
auto-deduce-content-type-when-requesting-data

Conversation

@Kybxd

@Kybxd Kybxd commented Oct 16, 2025

Copy link
Copy Markdown
Collaborator

@codecov

codecov Bot commented Oct 16, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.05%. Comparing base (cbe3a6b) to head (4e17b20).

Files with missing lines Patch % Lines
request.go 90.90% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #49      +/-   ##
==========================================
+ Coverage   80.19%   83.05%   +2.85%     
==========================================
  Files           7        7              
  Lines         409      360      -49     
==========================================
- Hits          328      299      -29     
+ Misses         59       38      -21     
- Partials       22       23       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread options.go Outdated
Comment on lines +213 to +214
// Data sets data of request body. It also deduces and sets the Content-Type
// for the input data.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more details for deducing different content types based on data types:

  1. "application/json": struct, slice(except []byte), and map
  2. auto deduce by [http.DetectContentType]: []byte, io.Reader
  3. "text/plain": others

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread request.go
Comment on lines +196 to +197
default:
return plainTextType, fmt.Appendf(nil, "%v", bodyValue.Interface()), nil

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the data type is io.Reader, we should also process it well. just like: https://github.com/go-resty/resty/blob/v3/middleware.go#L428C7-L428C16

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. We check if the input data implements io.Reader first before checking its reflect.Kind.

@wenchy

wenchy commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Code review

Found 2 issues:

  1. *[]byte is JSON/base64-marshaled instead of being treated as raw bytes. reflect.Indirect dereferences a *[]byte into a reflect.Slice, so the Slice case is entered, but the []byte type assertion is performed on the original (still *[]byte) data value and fails. The code then falls through to json.Marshal(data), which base64-encodes the bytes and returns application/json — contradicting the documented []byte behavior (use http.DetectContentType). The test suite has no *[]byte case, so this is uncaught. The assertion should be against the dereferenced value.

requests/request.go

Lines 189 to 199 in c6790f3

}
bodyValue := reflect.Indirect(reflect.ValueOf(data))
switch bodyValue.Kind() {
case reflect.Struct, reflect.Map, reflect.Slice:
// check slice here to differentiate between any slice vs byte slice
if body, ok := data.([]byte); ok {
return http.DetectContentType(body), body, nil
} else {
body, err := json.Marshal(data)
return jsonContentType, body, err
}

  1. Passing a typed nil pointer (e.g. Data((*MyStruct)(nil))) panics. A typed nil pointer assigned to any is a non-nil interface, so opts.Data != nil passes and deduceContentTypeAndBody runs. reflect.Indirect on a nil pointer returns an invalid zero reflect.Value (Kind() == reflect.Invalid), so the switch falls through to default, where bodyValue.Interface() panics with reflect: call of reflect.Value.Interface on zero Value. The pre-PR code used fmt.Sprintf("%v", opts.Data) which safely returned <nil>. Add a !bodyValue.IsValid() guard (or a nil check) before reaching bodyValue.Interface().

requests/request.go

Lines 189 to 202 in c6790f3

}
bodyValue := reflect.Indirect(reflect.ValueOf(data))
switch bodyValue.Kind() {
case reflect.Struct, reflect.Map, reflect.Slice:
// check slice here to differentiate between any slice vs byte slice
if body, ok := data.([]byte); ok {
return http.DetectContentType(body), body, nil
} else {
body, err := json.Marshal(data)
return jsonContentType, body, err
}
default:
return plainTextType, fmt.Appendf(nil, "%v", bodyValue.Interface()), nil
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

- Use the dereferenced reflect.Value for the []byte assertion so that
  *[]byte is treated as raw bytes (http.DetectContentType) instead of
  being JSON/base64-marshaled.
- Guard against invalid reflect.Value from typed nil pointers (e.g.
  (*T)(nil)) to avoid panicking on bodyValue.Interface().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@wenchy
wenchy merged commit 13db74d into master Jul 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Data: handle any type gracefully based on "Content-Type" of headers

2 participants