Plug and Phoenix integration for CSV downloads.
Requires the optional :plug dependency.
Staged export (recommended): send_staged_export/4
Streaming a database cursor straight to a slow HTTP client holds a database
connection for the whole download. send_staged_export/4 instead writes the
export to a private temporary file first, releases the database connection, and
then serves the file with Plug.Conn.send_file/3.
Trade-off: the response starts only after the whole export has been written, so
very large exports keep the request waiting (and can hit proxy or load balancer
timeouts). For those, run BeamExport.to_file/3 in a background job instead.
Chunked export: send_chunked_export/4
Streams chunks with chunked transfer encoding as they are produced. The database connection is held until the download finishes, so use it only for trusted, fast clients (internal tools, service-to-service).
Errors
Both functions raise when the export fails. send_staged_export/4 raises
BeamExport.ExportError before any response is sent (resulting in a 500 in
Phoenix). send_chunked_export/4 has already sent the status line when a
mid-stream error happens; the exception aborts the connection without the final
chunk, so HTTP clients detect the download as incomplete rather than receiving a
truncated file that looks complete.
Error messages never contain record data unless include_record_in_errors: true
is passed.
Summary
Functions
Streams CSV chunks directly to the client using chunked transfer encoding.
Exports source to a private temporary file, then sends it as a download.
Functions
@spec send_chunked_export( Plug.Conn.t(), String.t(), Enumerable.t() | {module(), Ecto.Queryable.t()}, keyword() ) :: Plug.Conn.t()
Streams CSV chunks directly to the client using chunked transfer encoding.
Stops reading the source as soon as the client disconnects. Holds the database
connection (for Ecto sources) for the whole download: prefer
send_staged_export/4 for public or slow clients.
Options
:content_type- defaults to"text/csv".:charset- defaults to"utf-8".- every option accepted by
BeamExport.to_stream/2.
@spec send_staged_export( Plug.Conn.t(), String.t(), Enumerable.t() | {module(), Ecto.Queryable.t()}, keyword() ) :: Plug.Conn.t()
Exports source to a private temporary file, then sends it as a download.
The temporary file lives in a new directory (mode 0700) under :tmp_dir
and is created with mode 0600. Both are deleted when the request process
exits, whether it finishes normally, crashes or the client disconnects.
Options
:tmp_dir- parent directory for temporary exports. Defaults toSystem.tmp_dir!(). Never pass user input here.:content_type- the response content type. Defaults to"text/csv", or"application/gzip"when the export is gzip-compressed (compress: trueor a filename ending in.gz).:charset- the content type charset. Defaults to"utf-8"(none for gzip).- every option accepted by
BeamExport.to_file/3.
filename is only used for the content-disposition header (sanitized,
RFC 6266 / RFC 5987 encoded) and the temporary file name (reduced to
[A-Za-z0-9._-]); it can never influence the temporary file's location.