Skip to main content

Stream one HTTP response as multiple parts. For Django, FastAPI, and Starlette.

Project description

multipart-response

Stream one HTTP response as multiple parts. For Django, FastAPI, and Starlette.

FastAPI

Install the FastAPI adapter:

uv add "multipart-response[fastapi]"

Yield parts from an endpoint:

from fastapi import FastAPI
from multipart_response.fastapi import HTMLMultipartResponse

app = FastAPI()

@app.get("/updates", response_class=HTMLMultipartResponse)
async def updates():
    yield "<p>Ready</p>"
    yield "<p>Done</p>"

Each part is sent when it is yielded:

Content-Type: multipart/mixed; boundary=multipart-...

--multipart-...
content-length: 12
content-type: text/html; charset=utf-8

<p>Ready</p>
--multipart-...
content-length: 11
content-type: text/html; charset=utf-8

<p>Done</p>
--multipart-...--

The same API is available from multipart_response.starlette.

Django

Install the Django adapter:

uv add "multipart-response[django]"

Return explicit parts from a view:

from multipart_response.django import MultipartResponse, Part


def updates(request):
    def parts():
        yield Part("<p>Ready</p>")
        yield Part("<p>Done</p>")

    return MultipartResponse(parts())

Part uses Django's content, content_type, charset, and headers conventions. HTML is the default content type, as it is for Django's HttpResponse.

Set headers on one part through its constructor or headers:

part = Part(
    "<p>Ready</p>",
    headers={"HX-Target": "#status"},
)
part.headers["HX-Swap"] = "innerHTML"

Use an async part source when Django runs under ASGI:

async def updates(request):
    async def parts():
        yield Part("<p>Ready</p>")
        yield Part("<p>Done</p>")

    return MultipartResponse(parts())

MultipartResponse subclasses Django's StreamingHttpResponse, so Django handles it like any other streaming response.

Django 4.2 or later is required. Sync iterators suit WSGI. Async iterators suit ASGI.

htmx

With the hx-multipart extension, each part is one swap. Part headers pick the target:

@app.get("/dashboard", response_class=HTMLMultipartResponse)
async def dashboard():
    yield ("<p>Ready</p>", {"HX-Target": "#status"})
    yield ("<li>New</li>", {"HX-Target": "#reports", "HX-Swap": "beforeend"})

Other part types

Use explicit parts when one response mixes content types:

from multipart_response.fastapi import JSONPart, Multipart, MultipartResponse, Part, TextPart

@app.get("/report", response_class=MultipartResponse)
async def report():
    yield TextPart("Preparing")
    yield JSONPart({"status": "ready"})
    yield Part(chunk_stream(), media_type="video/mp4")
    yield Multipart([...], subtype="alternative")

Django's Part uses content_type instead of media_type. Use JSONPart for Django's JsonResponse serialization rules.

Notes

  • Return MultipartResponse([...], status_code=..., headers=...) with FastAPI or Starlette.
  • Return MultipartResponse([...], status=..., reason=..., headers=...) with Django.
  • The dependency-free core exports Multipart, MultipartPart, and MultipartWriter.
  • Boundaries and headers are validated against RFC 2046 limits.
  • Body chunks are checked for boundary collisions.

License

BSD-3-Clause

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

multipart_response-0.3.0.tar.gz (72.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

multipart_response-0.3.0-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

File details

Details for the file multipart_response-0.3.0.tar.gz.

File metadata

  • Download URL: multipart_response-0.3.0.tar.gz
  • Upload date:
  • Size: 72.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for multipart_response-0.3.0.tar.gz
Algorithm Hash digest
SHA256 1b2650bdd14acfcb66039bc72ded02c27f44dd8f1aef90243ac65b845dd4dcd1
MD5 dac979643f54e9b4309848c3cad3a372
BLAKE2b-256 f1f699ad170307de86d3807c71141626b3fedced6af84c5fcafe165d094c114b

See more details on using hashes here.

Provenance

The following attestation bundles were made for multipart_response-0.3.0.tar.gz:

Publisher: release.yml on scriptogre/multipart-response

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file multipart_response-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for multipart_response-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8f9b0b5e95521296302aa4433d7d9070ca748fa0593294f11df13ab43992bef5
MD5 fd609a479c8e84f82676cc0a6e364c90
BLAKE2b-256 893d332339509378cd5660020312fe5aaaf411e3e23cd6d52f547b27c744a2ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for multipart_response-0.3.0-py3-none-any.whl:

Publisher: release.yml on scriptogre/multipart-response

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page