Supabase. Fetcher. Multipart
(supabase_potion v1.0.0)
Copy Markdown
Provides multipart/form-data encoding for file uploads and form submissions.
Wraps the multipart library with a Supabase-friendly API.
Part Types
{:file, binary, opts}- File from memory{:file_path, path, opts}- File from disk (streaming){:field, name, value}- Text field{:field, name, value, opts}- Text field with options
Examples
parts = [
{:file_path, "/path/to/doc.pdf", name: "document"},
{:field, "description", "Monthly report"}
]
{content_type, body} = Supabase.Fetcher.Multipart.encode(parts)File Upload from Memory
file_binary = File.read!("report.pdf")
parts = [
{:file, file_binary,
name: "document",
filename: "report.pdf",
content_type: "application/pdf"}
]
Supabase.Functions.invoke(client, "upload", body: {:multipart, parts})File Upload from Disk (Streaming)
parts = [
{:file_path, "/path/to/large-video.mp4", name: "video"}
]
Supabase.Functions.invoke(client, "process-video", body: {:multipart, parts})Multiple Files with Metadata
parts = [
{:file_path, "/path/to/image1.jpg", name: "photos", filename: "photo1.jpg"},
{:file_path, "/path/to/image2.jpg", name: "photos", filename: "photo2.jpg"},
{:field, "album", "Vacation 2025"},
{:field, "tags", "beach,sunset"}
]
Supabase.Functions.invoke(client, "upload-album", body: {:multipart, parts})Phoenix/Plug Integration
def upload_to_function(conn, _params) do
%Plug.Upload{path: path, filename: filename, content_type: type} =
conn.params["file"]
parts = [
{:file_path, path,
name: "file",
filename: filename,
content_type: type},
{:field, "user_id", conn.assigns.user_id}
]
case Supabase.Functions.invoke(client, "process-upload",
body: {:multipart, parts}) do
{:ok, response} -> json(conn, response.body)
{:error, error} -> put_status(conn, 500) |> json(%{error: error})
end
endLarge File Streaming
parts = [
{:file_path, "/path/to/huge-file.zip", name: "backup"}
]
# Use multipart_stream for very large files
Supabase.Functions.invoke(client, "backup",
body: {:multipart_stream, parts},
timeout: 60_000 # 1 minute timeout
)
Summary
Functions
Calculates the total content length without loading files into memory.
Encodes parts as multipart/form-data.
Encodes parts as streaming multipart/form-data.
Types
Functions
@spec content_length(parts()) :: non_neg_integer()
Calculates the total content length without loading files into memory.
This is useful for setting the Content-Length header or for progress tracking.
Examples
parts = [
{:file_path, "/path/to/file.pdf", name: "document"}
]
length = Multipart.content_length(parts)
# => 524288 (bytes)
Encodes parts as multipart/form-data.
Returns {content_type, body} where content_type includes the boundary.
Body is returned as iodata for efficient memory usage.
Options for file parts
:name(required) - Form field name:filename- Custom filename (defaults to basename for file_path):content_type- Custom content-type (defaults to auto-detection)
Options for field parts
:content_type- Custom content-type (defaults to none)
Examples
parts = [
{:file, "PDF content", name: "doc", filename: "report.pdf"},
{:field, "description", "Q4 Report"}
]
{content_type, body} = Multipart.encode(parts)
# => {"multipart/form-data; boundary=...", <<...>>}
@spec encode_stream(parts()) :: {content_type :: String.t(), stream :: Enumerable.t()}
Encodes parts as streaming multipart/form-data.
Returns {content_type, stream} where stream is an Enumerable.
Useful for large file uploads to reduce memory usage.
Examples
parts = [{:file_path, "/large/file.zip", name: "backup"}]
{content_type, stream} = Multipart.encode_stream(parts)
# Stream can be consumed chunk by chunk
Enum.each(stream, fn chunk ->
# Process chunk
end)