Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writer based ResponseBody #3258

Open
1 task done
mineichen opened this issue Mar 10, 2025 · 2 comments
Open
1 task done

Writer based ResponseBody #3258

mineichen opened this issue Mar 10, 2025 · 2 comments

Comments

@mineichen
Copy link

mineichen commented Mar 10, 2025

  • I have looked for existing issues (including closed) about this

Feature Request

Motivation

I'm using async_zip to send data directly to the client. async_zip::core::ZipFileWriter::new accepts a param, which implements AsyncWrite. Afterwards, i can asynchronously add files to the ZipFileWriter, and the encoded/compressed data is written to the underlying writer. Unfortunately, I couldn't get a hand on a writer for the HttpBody.

Proposal

I came up with a new IntoResponse type, which accepts a closure that returns a future. As long as the future is not finished, it's able to write data to the writer. You can find a naive implementation here. The usage of that type looks like this:

IoStreamBody::with_writer(move |mut w| {
    async move {
       w.write_all(b"Hello").await?;
       Ok(())
    }
}),

This will allow easy integration with async_zip and it will potentially be easier to imlement allocation-free data-streams, as we never need to represent the data to be returned as a owned byte-slice.

Alternatives

Just leave this to the user, as it can be implemented today.
I don't know, how important backward compatibility is... Maybe It could be implemented with AsyncFn instead?
Such a IntoResponse-Type could also life in the axum-extras project. The Error type should most likely not be anyhow::Error (as in the poc implementation).

@mladedav
Copy link
Collaborator

mladedav commented Mar 10, 2025

You don't need a new type, you can just use ReaderStream to convert your Reader into a Stream and then Body::from_stream.

Does that solve your issue?

@mineichen
Copy link
Author

It could be part of the implementation, but there is more to it.
I don't just have a AsyncRead, but I have to create one, e.g. with piper. But now I have drive the future which fills the pipe somewhere. In my implementation I do this as part of the Stream( the easiest way is, to just spawn a tokio task, but in a complete implementation I have to handle Errors/Panics of this task so it can be related to the Request and is not just a "global error").

I aggree, that this doesn't have to be directly related to axum, but outside axum, we need to go through a indirection (e.g. Piper), but axum has the possibility to expose the writer with access to the RequestSocket, if it's implemented by axum itself and not in axum-extra.

It would be another paradigm, and other Languages/Frameworks (e.g. Dotnet) allow you to write to the http-body instead of returning a value from the handler which is then written by the framework. It would be nice to have something like that, because it wasn't obvious to me how I can use AsyncFileWriter without a intermediate Buffer. A junior dev might even think, that this is not possible with axum.

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

No branches or pull requests

2 participants