# QuestDB REST API Python Client, CLI and REPL Shell
> QuestDB comes with a very nice web console, but there's no CLI, so I wrote one (can't live without the terminal!).
The REST API is very well defined: https://questdb.com/docs/reference/api/rest/, only 3 documented endpoints. One undocumented endpoints I also implemented are `/chk` to check for if a table exists, I found the route when trying to ingest CSV via the web console.
- [QuestDB REST API Python Client, CLI and REPL Shell](#questdb-rest-api-python-client-cli-and-repl-shell)
- [Features beyond what the vanilla REST API provides](#features-beyond-what-the-vanilla-rest-api-provides)
- [Docs, screenshots and video demos](#docs-screenshots-and-video-demos)
- [`imp` programmatically derives table name from filename when uploading CSVs](#imp-programmatically-derives-table-name-from-filename-when-uploading-csvs)
- [`exec` supports multiple queries in one go](#exec-supports-multiple-queries-in-one-go)
- [Query output parsing and formatting](#query-output-parsing-and-formatting)
- [`schema`](#schema)
- [`chk`](#chk)
- [Usage](#usage)
- [Global options to fine tune log levels](#global-options-to-fine-tune-log-levels)
- [Configuring CLI - DB connection options](#configuring-cli---db-connection-options)
- [PyPI packages and installation](#pypi-packages-and-installation)
- [The Python API](#the-python-api)
- [Screenshots](#screenshots)
## Features beyond what the vanilla REST API provides
### Docs, screenshots and video demos
Originally I just wrote the CLI (`cli.py`), then it becomes really complicated that I had to split the code and put the REST API interfacing part into a module (`__init__.py`).
- Write up and demo: https://teddysc.me/blog/questdb-rest
- https://teddysc.me/blog/rlwrap-questdb-shell
- GitHub: https://github.com/tddschn/questdb-rest
- PyPI: https://pypi.org/project/questdb-rest/
### `imp` programmatically derives table name from filename when uploading CSVs
`questdb-cli imp` options that are not part of the REST API spec:
```
--name-func {stem,add_prefix}
Function to generate table name from filename (ignored if --name set). Available: stem, add_prefix (default: None)
--name-func-prefix NAME_FUNC_PREFIX
Prefix string for 'add_prefix' name function. (default: )
-D, --dash-to-underscore
If table name is derived from filename (i.e., --name not set), convert dashes (-) to underscores (_). Compatible with --name-func. (default: False)
```
Global flag `--stop-on-error` controls if it should stop talking to the API on first CSV import error or not.
### `exec` supports multiple queries in one go
The API and web console will only take your last query if you attempt to give it more than 1, while this project uses `sqlparser` to split the queries and send them one by one for you for convenience. Global flag `--stop-on-error` controls if it should stop talking to the API on first error or not. Since the API doesn't always return a status code other than 200 on error, I dived in to the Dev Tools to see what exactly tells me if a request is successful or not.
The queries can be piped in from stdin, or read from a file, or you can supply it from the command line.
### Query output parsing and formatting
The `/exec` endpoints only speaks JSON, this tool gives you options to format the output table to as markdown with `--markdown` or a psql-style ASCII table with `--psql` (default is JSON).
For CSV output, use `questdb-cli exp` instead.
### `schema`
Convenience command to fetch schema for 1 or more tables. Hard to do without reading good chunk of the QuestDB doc. The web console supports copying schemas from the tables list.
```
qdb-cli schema equities_1d
CREATE TABLE 'equities_1d' (
timestamp TIMESTAMP,
open DOUBLE,
high DOUBLE,
low DOUBLE,
close DOUBLE,
volume LONG,
ticker SYMBOL CAPACITY 1024 CACHE
) timestamp(timestamp) PARTITION BY YEAR WAL
WITH maxUncommittedRows=500000, o3MaxLag=600000000us
DEDUP UPSERT KEYS(timestamp,ticker);
```
### `chk`
The `chk` command to talk to `/chk` endpoint, which is used by the web console's CSV upload UI.
## Usage
### Global options to fine tune log levels
```
qdb-cli -h
usage: questdb-cli [-h] [-H HOST] [--port PORT] [-u USER] [-p PASSWORD]
[--timeout TIMEOUT] [--scheme {http,https}] [-i | -D] [-R]
[--config CONFIG] [--stop-on-error | --no-stop-on-error]
{imp,exec,exp,chk,schema,gen-config} ...
QuestDB REST API Command Line Interface.
Logs to stderr, outputs data to stdout.
Uses QuestDB REST API via questdb_rest library.
positional arguments:
{imp,exec,exp,chk,schema,gen-config}
Available sub-commands
imp Import data from file(s) using /imp.
exec Execute SQL statement(s) using /exec (returns JSON).
Reads SQL from --query, --file, --get-query-from-python-module, or stdin.
exp Export data using /exp (returns CSV to stdout or file).
chk Check if a table exists using /chk (returns JSON). Exit code 0 if exists, 3 if not.
schema Fetch CREATE TABLE statement(s) for one or more tables.
gen-config Generate a default config file at ~/.questdb-rest/config.json
options:
-h, --help Show this help message and exit.
-H HOST, --host HOST QuestDB server host.
--port PORT QuestDB REST API port.
-u USER, --user USER Username for basic authentication.
-p PASSWORD, --password PASSWORD
Password for basic authentication. If -u is given but -p is not, will prompt securely unless password is in config.
--timeout TIMEOUT Request timeout in seconds.
--scheme {http,https}
Connection scheme (http or https).
-i, --info Use info level logging (default is WARNING).
-D, --debug Enable debug level logging to stderr.
-R, --dry-run Simulate API calls without sending them. Logs intended actions.
--config CONFIG Path to a specific config JSON file (overrides default ~/.questdb-rest/config.json).
--stop-on-error, --no-stop-on-error
Stop execution immediately if any item (file/statement/table) fails.
```
### Configuring CLI - DB connection options
Run `qdb-cli gen-config` and edit the generated config file to specify your DB's port, host, and auth info.
All options are optional and will use the default `localhost:9000` if not specified.
## PyPI packages and installation
`questdb-cli`, `questdb-rest` and `questdb-api` are the same package (just aliases), with `questdb-rest` guaranteed to be the most updated.
Installing any of them will give you the `questdb-cli` and `qdb-cli` commands (same thing).
Install (Python >=3.11 required):
```bash
uv tool install questdb-rest
```
```bash
pipx install questdb-rest
```
```bash
# not recommended, but if you really want to:
pip install questdb-rest
```
## The Python API
These classes are provided with extensive methods to interact with the REST API (it's all in `__init__.py`).
```plain
QuestDBError
QuestDBConnectionError
QuestDBAPIError
QuestDBClient
```
## Screenshots




Raw data
{
"_id": null,
"home_page": "https://github.com/tddschn/questdb-rest",
"name": "questdb-rest",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "questdb, rest, api, wrapper, client, http",
"author": "Teddy Xinyuan Chen",
"author_email": "45612704+tddschn@users.noreply.github.com",
"download_url": "https://files.pythonhosted.org/packages/f4/ef/2a99f6f0bf7a864f812e53f94766548a8d18da2d17692afd6a560525b4eb/questdb_rest-1.3.5.tar.gz",
"platform": null,
"description": "# QuestDB REST API Python Client, CLI and REPL Shell\n\n> QuestDB comes with a very nice web console, but there's no CLI, so I wrote one (can't live without the terminal!).\n\nThe REST API is very well defined: https://questdb.com/docs/reference/api/rest/, only 3 documented endpoints. One undocumented endpoints I also implemented are `/chk` to check for if a table exists, I found the route when trying to ingest CSV via the web console.\n\n- [QuestDB REST API Python Client, CLI and REPL Shell](#questdb-rest-api-python-client-cli-and-repl-shell)\n - [Features beyond what the vanilla REST API provides](#features-beyond-what-the-vanilla-rest-api-provides)\n - [Docs, screenshots and video demos](#docs-screenshots-and-video-demos)\n - [`imp` programmatically derives table name from filename when uploading CSVs](#imp-programmatically-derives-table-name-from-filename-when-uploading-csvs)\n - [`exec` supports multiple queries in one go](#exec-supports-multiple-queries-in-one-go)\n - [Query output parsing and formatting](#query-output-parsing-and-formatting)\n - [`schema`](#schema)\n - [`chk`](#chk)\n - [Usage](#usage)\n - [Global options to fine tune log levels](#global-options-to-fine-tune-log-levels)\n - [Configuring CLI - DB connection options](#configuring-cli---db-connection-options)\n - [PyPI packages and installation](#pypi-packages-and-installation)\n - [The Python API](#the-python-api)\n - [Screenshots](#screenshots)\n\n\n## Features beyond what the vanilla REST API provides\n\n\n### Docs, screenshots and video demos\n\nOriginally I just wrote the CLI (`cli.py`), then it becomes really complicated that I had to split the code and put the REST API interfacing part into a module (`__init__.py`).\n\n- Write up and demo: https://teddysc.me/blog/questdb-rest\n- https://teddysc.me/blog/rlwrap-questdb-shell\n- GitHub: https://github.com/tddschn/questdb-rest\n- PyPI: https://pypi.org/project/questdb-rest/\n\n### `imp` programmatically derives table name from filename when uploading CSVs\n\n`questdb-cli imp` options that are not part of the REST API spec:\n```\n --name-func {stem,add_prefix}\n Function to generate table name from filename (ignored if --name set). Available: stem, add_prefix (default: None)\n --name-func-prefix NAME_FUNC_PREFIX\n Prefix string for 'add_prefix' name function. (default: )\n -D, --dash-to-underscore\n If table name is derived from filename (i.e., --name not set), convert dashes (-) to underscores (_). Compatible with --name-func. (default: False)\n```\n\nGlobal flag `--stop-on-error` controls if it should stop talking to the API on first CSV import error or not.\n\n### `exec` supports multiple queries in one go\n\nThe API and web console will only take your last query if you attempt to give it more than 1, while this project uses `sqlparser` to split the queries and send them one by one for you for convenience. Global flag `--stop-on-error` controls if it should stop talking to the API on first error or not. Since the API doesn't always return a status code other than 200 on error, I dived in to the Dev Tools to see what exactly tells me if a request is successful or not.\n\nThe queries can be piped in from stdin, or read from a file, or you can supply it from the command line.\n\n\n\n### Query output parsing and formatting\n\nThe `/exec` endpoints only speaks JSON, this tool gives you options to format the output table to as markdown with `--markdown` or a psql-style ASCII table with `--psql` (default is JSON).\n\nFor CSV output, use `questdb-cli exp` instead.\n\n### `schema`\n\nConvenience command to fetch schema for 1 or more tables. Hard to do without reading good chunk of the QuestDB doc. The web console supports copying schemas from the tables list.\n\n```\nqdb-cli schema equities_1d\n\nCREATE TABLE 'equities_1d' ( \n\ttimestamp TIMESTAMP,\n\topen DOUBLE,\n\thigh DOUBLE,\n\tlow DOUBLE,\n\tclose DOUBLE,\n\tvolume LONG,\n\tticker SYMBOL CAPACITY 1024 CACHE\n) timestamp(timestamp) PARTITION BY YEAR WAL\nWITH maxUncommittedRows=500000, o3MaxLag=600000000us\nDEDUP UPSERT KEYS(timestamp,ticker);\n```\n### `chk`\n\nThe `chk` command to talk to `/chk` endpoint, which is used by the web console's CSV upload UI.\n\n## Usage\n\n### Global options to fine tune log levels\n\n```\nqdb-cli -h\n\nusage: questdb-cli [-h] [-H HOST] [--port PORT] [-u USER] [-p PASSWORD]\n [--timeout TIMEOUT] [--scheme {http,https}] [-i | -D] [-R]\n [--config CONFIG] [--stop-on-error | --no-stop-on-error]\n {imp,exec,exp,chk,schema,gen-config} ...\nQuestDB REST API Command Line Interface.\nLogs to stderr, outputs data to stdout.\nUses QuestDB REST API via questdb_rest library.\npositional arguments:\n {imp,exec,exp,chk,schema,gen-config}\n Available sub-commands\n imp Import data from file(s) using /imp.\n exec Execute SQL statement(s) using /exec (returns JSON).\n Reads SQL from --query, --file, --get-query-from-python-module, or stdin.\n exp Export data using /exp (returns CSV to stdout or file).\n chk Check if a table exists using /chk (returns JSON). Exit code 0 if exists, 3 if not.\n schema Fetch CREATE TABLE statement(s) for one or more tables.\n gen-config Generate a default config file at ~/.questdb-rest/config.json\noptions:\n -h, --help Show this help message and exit.\n -H HOST, --host HOST QuestDB server host.\n --port PORT QuestDB REST API port.\n -u USER, --user USER Username for basic authentication.\n -p PASSWORD, --password PASSWORD\n Password for basic authentication. If -u is given but -p is not, will prompt securely unless password is in config.\n --timeout TIMEOUT Request timeout in seconds.\n --scheme {http,https}\n Connection scheme (http or https).\n -i, --info Use info level logging (default is WARNING).\n -D, --debug Enable debug level logging to stderr.\n -R, --dry-run Simulate API calls without sending them. Logs intended actions.\n --config CONFIG Path to a specific config JSON file (overrides default ~/.questdb-rest/config.json).\n --stop-on-error, --no-stop-on-error\n Stop execution immediately if any item (file/statement/table) fails.\n```\n\n### Configuring CLI - DB connection options\n\nRun `qdb-cli gen-config` and edit the generated config file to specify your DB's port, host, and auth info.\n\nAll options are optional and will use the default `localhost:9000` if not specified.\n\n## PyPI packages and installation\n\n`questdb-cli`, `questdb-rest` and `questdb-api` are the same package (just aliases), with `questdb-rest` guaranteed to be the most updated.\n\nInstalling any of them will give you the `questdb-cli` and `qdb-cli` commands (same thing).\n\nInstall (Python >=3.11 required):\n\n```bash\nuv tool install questdb-rest\n```\n\n```bash\npipx install questdb-rest\n```\n\n```bash\n# not recommended, but if you really want to:\npip install questdb-rest\n```\n\n\n## The Python API\n\nThese classes are provided with extensive methods to interact with the REST API (it's all in `__init__.py`).\n\n```plain\nQuestDBError\nQuestDBConnectionError\nQuestDBAPIError\nQuestDBClient\n```\n\n## Screenshots\n\n\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "QuestDB REST API Python client library and CLI",
"version": "1.3.5",
"project_urls": {
"Bug Tracker": "https://github.com/tddschn/questdb-rest/issues",
"Homepage": "https://github.com/tddschn/questdb-rest",
"Repository": "https://github.com/tddschn/questdb-rest"
},
"split_keywords": [
"questdb",
" rest",
" api",
" wrapper",
" client",
" http"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "dd4b3bae6a27603eaee6bbd733364780b6b6a91375059cff18f4fbea37531c7a",
"md5": "6b5752b16e45d9c01901bf17d4addb1c",
"sha256": "9c2adb448bebb06a76898ffadb2da7a5baa4d083f296b43383d61ee63fff83d3"
},
"downloads": -1,
"filename": "questdb_rest-1.3.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6b5752b16e45d9c01901bf17d4addb1c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 25758,
"upload_time": "2025-03-31T23:45:50",
"upload_time_iso_8601": "2025-03-31T23:45:50.015520Z",
"url": "https://files.pythonhosted.org/packages/dd/4b/3bae6a27603eaee6bbd733364780b6b6a91375059cff18f4fbea37531c7a/questdb_rest-1.3.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f4ef2a99f6f0bf7a864f812e53f94766548a8d18da2d17692afd6a560525b4eb",
"md5": "59022d2ff24be38caa76a6a78cb7959a",
"sha256": "e80a876a0caf30e2d3ad85ac25fbfbd507dd0110dec403414c684b94458a5f71"
},
"downloads": -1,
"filename": "questdb_rest-1.3.5.tar.gz",
"has_sig": false,
"md5_digest": "59022d2ff24be38caa76a6a78cb7959a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 26478,
"upload_time": "2025-03-31T23:45:51",
"upload_time_iso_8601": "2025-03-31T23:45:51.553935Z",
"url": "https://files.pythonhosted.org/packages/f4/ef/2a99f6f0bf7a864f812e53f94766548a8d18da2d17692afd6a560525b4eb/questdb_rest-1.3.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-03-31 23:45:51",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "tddschn",
"github_project": "questdb-rest",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "questdb-rest"
}