# Use Cases

## Handling Streaming Responses

In addition to receiving responses with `IResponse.deliverBody()`, treq provides a helper function `treq.collect()` which takes a `response` and a single argument function which will be called with all new data available from the response. Much like `IProtocol.dataReceived()`, `treq.collect()` knows nothing about the framing of your data and will simply call your collector function with any data that is currently available.

By default, treq buffers the full response in memory. Pass `unbufferred=True` to disable this behavior.

Here is an example which simply a file object’s write method to `treq.collect()` to save the response body to a file.

    async def download_file(reactor, url, destination_filename):
        with open(destination_filename, "wb") as destination:
            response = await treq.get(url, unbuffered=True)
            await treq.collect(response, destination.write)

Full example: `download_file.py`

## URLs, URIs, and Hyperlinks

The url argument to `HTTPClient.request()` accepts three URL representations:

- High-level: `hyperlink.DecodedURL`

- Mid-level `str` (`unicode` on Python 2)

- Low-level: ASCII `bytes` or `hyperlink.URL`

The high-level `DecodedURL` form is useful when programatically generating URLs. Here is an example that builds a URL that contains a `&` character, which is automatically escaped properly.

    async def basic_url(reactor):
        url = (
            DecodedURL.from_text("https://httpbin.org")
            .child("get")  # add path /get
            .add("foo", "&")  # add query ?foo=%26
        )
        print(url.to_text())
        await print_response(await treq.get(url))

Full example: `basic_url.py`

## Query Parameters

`treq.HTTPClient.request()` supports a `params` keyword argument which will be URL-encoded and added to the `url` argument in addition to any query parameters that may already exist.

The `params` argument may be either a `dict` or a `list` of `(key, value)` tuples.

If it is a `dict` then the values in the dict may either be scalar values or a `list` or `tuple` thereof. Scalar values means `str`, `bytes`, or anything else — even `None` — which will be coerced to `str`. Strings are UTF-8 encoded.

    async def query_params(reactor):
        print("List of tuples")
        resp = await treq.get(
            "https://httpbin.org/get", params=[("foo", "bar"), ("baz", "bax")]
        )
        print(await resp.text())

        print("Single value dictionary")
        resp = await treq.get(
            "https://httpbin.org/get", params={"foo": "bar", "baz": "bax"}
        )
        print(await resp.text())

        print("Multi value dictionary")
        resp = await treq.get(
            "https://httpbin.org/get", params={b"foo": [b"bar", b"baz", b"bax"]}
        )
        print(await resp.text())

        print("Mixed value dictionary")
        resp = await treq.get(
            "https://httpbin.org/get",
            params={"foo": [1, 2, 3], "bax": b"quux", b"bar": "foo"},
        )
        print(await resp.text())

        print("Preserved query parameters")
        resp = await treq.get("https://httpbin.org/get?foo=bar", params={"baz": "bax"})
        print(await resp.text())

Full example: `query_params.py`

If you prefer a strictly-typed API, try `hyperlink.DecodedURL`. Its `add()` and `set()` methods manipulate query parameters without risk of accidental type coercion.

## JSON

`HTTPClient.request()` supports a json keyword argument that gives a data structure to serialize as JSON (using `json.dumps()`). This also implies a `Content-Type: application/json` request header. The json parameter is mutually-exclusive with data.

The `_Response.json()` method decodes a JSON response body. It buffers the whole response and decodes it with `json.loads()`.

    async def json_post(reactor):
        response = await treq.post(
            "https://httpbin.org/post",
            json={"msg": "Hello!"},
        )
        data = await response.json()
        pprint(data)

Full example: `json_post.py`

## Auth

HTTP Basic authentication as specified in RFC 2617 is easily supported by passing an `auth` keyword argument to any of the request functions.

The `auth` argument should be a tuple of the form `('username', 'password')`.

    async def basic_auth(reactor):
        resp = await treq.get(
            "https://httpbin.org/basic-auth/treq/treq",
            auth=("treq", "treq"),
        )
        await print_response(resp)

Full example: `basic_auth.py`

## Redirects

treq handles redirects by default.

The following will print a 200 OK response.

    async def redirects(reactor):
        resp = await treq.get("https://httpbin.org/redirect/1")
        await print_response(resp)

Full example: `redirects.py`

You can easily disable redirects by simply passing `allow_redirects=False` to any of the request methods.

    async def disable_redirects(reactor):
        resp = await treq.get(
            "https://httpbin.org/redirect/1",
            allow_redirects=False,
        )
        await print_response(resp)

Full example: `disable_redirects.py`

You can even access the complete history of treq response objects by calling the `history()` method on the response.

    async def response_history(reactor):
        resp = await treq.get("https://httpbin.org/redirect/1")
        print("Response history:")
        print(resp.history())
        await print_response(resp)

Full example: `response_history.py`

## Cookies

Cookies can be set by passing a `dict` or `http.cookiejar.CookieJar` instance via the cookies keyword argument. Any cookies set by the server can be retrieved using the `cookies()` response method, which returns a `CookieJar`.

Use `treq.cookies.search()` to extract cookies from the jar:

    async def using_cookies(reactor):
        resp = await treq.get("https://httpbin.org/cookies/set?hello=world")

        jar = resp.cookies()
        [cookie] = treq.cookies.search(jar, domain="httpbin.org", name="hello")
        print(f"The server set our hello cookie to: {cookie.value!r}")

        response = await treq.get("https://httpbin.org/cookies", cookies=jar)
        await print_response(response)

Full example: `using_cookies.py`

## Customizing the Twisted Agent

The main `treq` module has helper functions that automatically instantiate an instance of `treq.client.HTTPClient`. You can create an instance of `HTTPClient` directly in order to customize the parameters used to initialize it. Internally, the `HTTPClient` wraps an instance of `twisted.web.client.Agent`. When you create an instance of `HTTPClient`, you must initialize it with an instance of `Agent`. This allows you to customize its behavior.

    async def custom_agent(reactor):
        my_agent = Agent(reactor, connectTimeout=42)
        http_client = HTTPClient(my_agent)
        resp = await http_client.get(
            "https://secure.example.net/area51",
            auth=("admin", "you'll never guess!"),
        )
        await print_response(resp)

Full example: `custom_agent.py`