Skip to content

[ingress client] Accept httpx-compatible clients without requiring httpx #247

Closed

Description

@maksimzayats

Related to #231. We use httpx2 in our application and supply our own async HTTP client to Restate. We still need to install httpx and httpcore because restate.client imports httpx at module level.

Could we allow compatible async HTTP clients while keeping the existing httpx behavior?

Reproduction

Reproduced with Python 3.12.14 and restate-sdk 1.1.0 in a clean virtual environment:

python3.12 -m venv /tmp/restate-client-repro
/tmp/restate-client-repro/bin/python -m pip install restate-sdk==1.1.0
/tmp/restate-client-repro/bin/python -c "from restate.client import Client"

The import fails with:

ModuleNotFoundError: No module named 'httpx'

The module-level import is also present on main. The client extra makes httpx optional, but this import prevents callers from using another compatible client on its own.

Proposed fix

  • Use small HttpClient and HttpResponse protocols. The client needs async post(url, *, headers, content). The response needs read-only status_code, reason_phrase, text and content fields.
  • Load the selected HTTP package inside create_client(). Keep httpx as the default. Keep the three existing positional arguments. Add keyword-only backend="httpx2" to select httpx2.
  • Keep client = ["httpx[http2]"]. Add a separate client-httpx2 = ["httpx2[http2]>=2.12,<3"] extra. Add no base dependency.
  • Require the selected package. Report its install command when it is missing. Do not fall back to the other package. Pass through broken imports inside an installed package.
  • Preserve Client.client, existing public names, requests, headers, codecs, return values and HttpError fields. Keep each client's own transport errors. Keep Python 3.10 support and leave the harness unchanged.

PR #248 implements this approach and credits Arthur's work in #231.

Activity

  1. igalshilman commented on Nov 9, 2026

    @igalshilman
    Contributor

    This is covered by #277: restate.client now imports only httpx2, and the client extra is httpx2[http2], so from restate.client import Client no longer needs httpx or httpcore. A Client can also be built over an AsyncClient you create yourself. If you need a client other than httpx2, say so and we can look at the protocol approach then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions