๐ฅ feat: Add StreamResponseBody support for the Client
This pull request introduces support for streaming HTTP response bodies in the client, allowing responses to be read as streams rather than being fully loaded into memory. This is particularly useful for handling large responses or server-sent events. The changes include new configuration options at both the client and request levels, implementation of the streaming logic, and comprehensive tests to ensure correct behavior.
Streaming response body support:
- Added a
streamResponseBodyfield to theClientstruct, along withSetStreamResponseBodyandStreamResponseBodymethods to enable or disable response body streaming at the client level (client/client.go). [1] [2] - Added a
streamResponseBodyfield to theRequeststruct, with correspondingSetStreamResponseBodyandStreamResponseBodymethods to allow per-request configuration that overrides the client setting (client/request.go). [1] [2] - Updated the request execution logic to set and restore the underlying HTTP client's streaming option based on the request or client configuration (
client/core.go). - Implemented the
BodyStreammethod on theResponsestruct to provide anio.Readerfor streaming the response body, falling back to an in-memory reader if streaming is not enabled (client/response.go).
Testing and validation:
- Added extensive tests to verify streaming behavior, including tests for server-sent events, large responses, default and overridden settings, and chainable configuration methods (
client/client_test.go,client/response_test.go). [1] [2] - Ensured that request resetting clears the
streamResponseBodyoverride (client/request.go).# Description
Please provide a clear and concise description of the changes you've made and the problem they address. Include the purpose of the change, any relevant issues it solves, and the benefits it brings to the project. If this change introduces new features or adjustments, highlight them here.
Related #3425
Thanks for opening this pull request! ๐ Please check out our contributing guidelines. If you need help or want to chat with us, join us on Discord https://gofiber.io/discord
[!NOTE]
Other AI code review bot(s) detected
CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.
Walkthrough
Adds response-body streaming support across client API, transport implementations, and response handling: new Client StreamResponseBody/SetStreamResponseBody, Response.BodyStream()/IsStreaming, transport propagation (standard/host/lb), Save() streaming paths, request BodyStream forwarding, core resource-safety fixes, tests, and docs.
Changes
| Cohort / File(s) | Summary |
|---|---|
Client API \client/client.go`` |
Adds StreamResponseBody() bool and SetStreamResponseBody(enable bool) *Client that proxy to the transport. |
Response streaming \client/response.go`` |
Adds BodyStream() io.Reader and IsStreaming() bool; updates Save() to use streaming (BodyStream()/io.Copy) when available and adjusts error paths. |
Core request/response flow \client/core.go`` |
Forwards request BodyStream into fasthttp (SetBodyStream with ContentLength); guards deferred ReleaseResponse with nil check; swaps RawResponse safely and releases previous response to avoid leaks. |
Transport layer \client/transport.go`` |
Extends httpClientTransport with StreamResponseBody() / SetStreamResponseBody(enable bool); implements on standardClientTransport, hostClientTransport, and lbClientTransport with traversal/propagation across nested hosts. |
Tests โ response \client/response_test.go`` |
Adds extensive streaming tests (BodyStream, IsStreaming, large/chunked/progressive streams, SSE, Save to writer/file, write/close error helpers). |
Tests โ transport & client \client/transport_test.go`, `client/client_test.go`` |
Adds tests for streaming flag default/enable/disable and propagation across standard, host, LB, nested, and mixed transports; client-level getter/setter tests. |
Tests โ test stubs \client/core_test.go`` |
Adds StreamResponseBody() and SetStreamResponseBody(_ bool) stubs on blockingErrTransport to satisfy new transport API in tests. |
Tests โ ctx \ctx_test.go`` |
Two tests updated to call app.Test(req, TestConfig{Timeout: 5 * time.Second}) to set per-call timeout. |
Docs \docs/client/rest.md`` |
Documents StreamResponseBody() and SetStreamResponseBody(stream bool) and adds SetRetryConfig doc; no code changes. |
Sequence Diagram(s)
sequenceDiagram
participant User
participant Client
participant Transport
participant Core
participant fasthttp as "fasthttp.Client"
participant Response
User->>Client: SetStreamResponseBody(true)
Client->>Transport: SetStreamResponseBody(true)
Transport->>fasthttp: set internal streaming flag(s)
User->>Client: Do(request)
Client->>Core: executeRequest(...)
Core->>fasthttp: Do()/DoDeadline(request)
fasthttp-->>Core: *fasthttp.Response
alt request contains BodyStream
Core->>fasthttp: SetBodyStream(contentLen, reader)
end
Core-->>Client: build Response (wrap RawResponse)
User->>Response: IsStreaming()
Response-->>User: true/false
alt streaming response
User->>Response: BodyStream()
Response-->>User: io.Reader (stream)
User->>Response: Save(dest)
Response->>Response: io.Copy(BodyStream -> dest)
else non-streaming response
User->>Response: Body()
Response-->>User: []byte
User->>Response: Save(dest)
Response->>Response: io.Copy(bytes.Reader -> dest)
end
Estimated code review effort
๐ฏ 4 (Complex) | โฑ๏ธ ~45 minutes
- Focus areas:
- client/transport.go: lbClientTransport traversal and propagation logic for nested balancing clients.
- client/core.go: RawResponse swap, ReleaseResponse nil-guard, and BodyStream forwarding into fasthttp.
- client/response.go: Save() streaming vs non-streaming branches and resource handling.
- client/response_test.go & client/transport_test.go: many timing-sensitive streaming tests.
Possibly related issues
- gofiber/fiber#3425 โ Matches the feature request to add fasthttp StreamResponseBody support and Response.BodyStream()/IsStreaming; this PR implements those APIs.
Possibly related PRs
- gofiber/fiber#3774 โ Adds/extends transport abstractions that this change further extends with streaming getters/setters.
- gofiber/fiber#3799 โ Implements BodyStream()/IsStreaming and streaming-aware flows; strongly related at the streaming API surface.
Suggested reviewers
- sixcolors
- gaby
- ReneWerner87
Poem
๐
I nibble bytes that trickle soft and slow,
I ferry streams where wandering packets go,
From client burrow to the distant shore,
My tiny hops keep data flowing more. ๐ฅ
Pre-merge checks and finishing touches
โ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | โ ๏ธ Warning | Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
โ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | โ Passed | The title clearly summarizes the main feature: adding StreamResponseBody support to the Client. It is specific, concise, and directly reflects the primary change. |
| Description check | โ Passed | The description comprehensively covers the changes introduced, references related issues, explains the streaming support implementation, and documents testing efforts, aligning with template requirements. |
โจ Finishing touches
- [ ] ๐ Generate docstrings
๐งช Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
I will update the documentation if the approach seems sound enough.
[!WARNING] Gemini encountered an error creating the review. You can try again by commenting
/gemini review.
@Abhirup-99 The tests are failing. You can run them locally by running make tests
@gaby fixed the failing tests
Codecov Report
:x: Patch coverage is 96.42857% with 2 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 91.67%. Comparing base (c235f85) to head (0dfe1c3).
| Files with missing lines | Patch % | Lines |
|---|---|---|
| client/core.go | 80.00% | 1 Missing and 1 partial :warning: |
Additional details and impacted files
@@ Coverage Diff @@
## main #3711 +/- ##
==========================================
+ Coverage 91.66% 91.67% +0.01%
==========================================
Files 119 119
Lines 10096 10144 +48
==========================================
+ Hits 9254 9300 +46
- Misses 534 537 +3
+ Partials 308 307 -1
| Flag | Coverage ฮ | |
|---|---|---|
| unittests | 91.67% <96.42%> (+0.01%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
@Abhirup-99 To fix the alignment you can run make betteralign it will fix it for you
@gaby @Abhirup-99 hi, I have some questions.
I don't think the current tests cover streaming response scenarios. For example, Test_Client_StreamResponseBody_ServerSentEvents only reads from bodyStream once and asserts it contains the first message โ it doesn't verify that subsequent messages arrive incrementally, nor can it detect mid-stream disconnects or cases where the server writes and returns data progressively. In Test_Request_StreamResponseBody the server immediately returns the full string (c.SendString("Hello, World!")) with no chunked or delayed writes, so it can't validate chunked/streaming delivery or on-demand reads โ the client, even in streaming mode, would read the whole response at once.
@JIeJaitt Correct, the tests are not testing streaming, the server needs to stream the resp
@codex review
@gaby have updated the code.
@Abhirup-99
LGTM
/gemini review
Increased test coverage and added documentation. @gaby @ReneWerner87
@gaby @ReneWerner87 bump
We will check tomorrow(sickness weekend)
@Abhirup-99 can you check the linting and the last hints
@ReneWerner87 updated the code. Also, can I work on #3731 ? Checking lint is very difficult because make lint seems to fail for go 1.25.
@Abhirup-99 How exactly is the server streaming a response back to the client during the tests?
The creation of a BodyStream by the client is masking this
@Abhirup-99 How exactly is the server streaming a response back to the client during the tests?
The creation of a BodyStream by the client is masking this
Fixed this
@gaby can you check this out?
@codex review
PR #3830 got merged, and seems to start some work on refactoring the core execution logic.
@Abhirup-99 Can you merge the most recent changes to this PR and retry the Stream Writer change I requested some time ago?
I still think the CopyToResponse method from fasthttp still doesn't copy the stream body in this case, but I think we can start experimenting with how to add this via fasthttp or Fiber if we merge the most recent updates to this PR.
@gaby @griver please review now.
@grivera64 done
@gaby can you check this out?
@Abhirup-99 Can you take a look at the coverage report from the codecov workflow? I think a few of the low coverage lines can be covered with a few simple unit tests.
@grivera64 can you check now?