# Send Python HTTP queries and parse JSON rows

For a Python application using an HTTP client library, treat SQL errors and result data as different response paths. `json_each_row` produces one object per line, so parse each nonempty line rather than assuming the whole body is a single JSON array.

```python
import json
import os
import requests

response = requests.post(
    os.environ['COORDINATOR_HTTP_URL'],
    params={'database': 'data'},
    auth=(os.environ['COORDINATOR_USER'], os.environ['COORDINATOR_PASSWORD']),
    data='SELECT 1 AS value FORMAT json_each_row',
    timeout=10,
)
query_id = response.headers.get('X-Coordinator-Query-Id')
response.raise_for_status()
rows = [json.loads(line) for line in response.text.splitlines() if line]
print(rows)
```

## Keep failures diagnosable

Install the external `requests` package in the application's own environment. Store credentials outside source code and use external TLS protection for an untrusted network. Preserve a redacted error body and query identifier when raising an application error.

The timeout belongs to the HTTP client; SQL processing has a separate `max_execution_time` setting. Do not automatically replay a timed-out INSERT, since its result can be ambiguous. HTTP bound parameters and persistent sessions are unsupported. For application data, send encoded format input with SQL in the `query` URL parameter rather than concatenating values into SQL.

See [HTTP uploads and metadata](https://coordinatordb.com/docs/concepts/features/interfaces/http), [JSON rows](https://coordinatordb.com/docs/reference/formats/json/json-each-row) and [execution deadlines](https://coordinatordb.com/docs/reference/settings/session-settings/max-execution).
