| Name | apiout JSON |
| Version |
0.6.0
JSON |
| download |
| home_page | None |
| Summary | A flexible Python tool for fetching data from APIs and serializing responses using TOML configuration files |
| upload_time | 2025-10-24 09:34:41 |
| maintainer | None |
| docs_url | None |
| author | None |
| requires_python | >3.8.0 |
| license | MIT License
Copyright (c) 2025 Holger
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
|
| keywords |
api
json
toml
serialization
cli
http
rest
|
| VCS |
 |
| bugtrack_url |
|
| requirements |
No requirements were recorded.
|
| Travis-CI |
No Travis.
|
| coveralls test coverage |
|
[](https://pypi.org/project/apiout/)


[](https://codecov.io/gh/holgern/apiout)
# apiout
A flexible Python tool for fetching data from APIs and serializing responses using TOML
configuration files.
## Features
- **Config-driven API calls**: Define API endpoints, parameters, and authentication in
TOML files
- **Flexible serialization**: Map API responses to desired output formats using
configurable field mappings
- **Separate concerns**: Keep API configurations and serializers in separate files for
better organization
- **Default serialization**: Works without serializers - automatically converts objects
to dictionaries
- **Generator tool**: Introspect API responses and auto-generate serializer
configurations
## Installation
```bash
pip install -e .
```
## Quick Start
### 1. Basic Usage (No Serializers)
Create an API configuration file (`apis.toml`):
```toml
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
client_class = "Client"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
[apis.params]
latitude = 52.52
longitude = 13.41
current = ["temperature_2m"]
```
Run the API fetcher:
```bash
apiout run -c apis.toml --json
```
Without serializers, the tool will automatically convert the response objects to
dictionaries.
### 2. Using Serializers
Create a serializer configuration file (`serializers.toml`):
```toml
[serializers.openmeteo]
[serializers.openmeteo.fields]
latitude = "Latitude"
longitude = "Longitude"
timezone = "Timezone"
[serializers.openmeteo.fields.current]
method = "Current"
[serializers.openmeteo.fields.current.fields]
time = "Time"
temperature = "Temperature"
```
Update your API configuration to reference the serializer:
```toml
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
client_class = "Client"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo" # Reference the serializer
[apis.params]
latitude = 52.52
longitude = 13.41
current = ["temperature_2m"]
```
Run with both configurations:
```bash
apiout run --config apis.toml --serializers serializers.toml --json
```
### 3. Inline Serializers
You can also define serializers inline in the API configuration:
```toml
[serializers.openmeteo]
[serializers.openmeteo.fields]
latitude = "Latitude"
longitude = "Longitude"
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
```
Run with just the API config:
```bash
apiout run -c apis.toml --json
```
### 4. Config Directory
For cleaner configuration management, you can store reusable API configurations in
`~/.config/apiout/` and load them by name using the `--config` flag:
**Setup:**
Create config files in `~/.config/apiout/`:
```bash
# ~/.config/apiout/mempool.toml
[clients.mempool]
module = "requests"
client_class = "Session"
[serializers.mempool.block_data]
[serializers.mempool.block_data.fields]
hash = "id"
height = "height"
timestamp = "timestamp"
[[apis]]
name = "mempool_blocks"
client = "mempool"
method = "get"
url = "https://mempool.space/api/v1/blocks"
serializer = "block_data"
```
```bash
# ~/.config/apiout/btcprice.toml
[clients.btc_price]
module = "requests"
client_class = "Session"
[serializers.btc_price.price_data]
[serializers.btc_price.price_data.fields]
usd = "bitcoin.usd"
eur = "bitcoin.eur"
[[apis]]
name = "btc_price"
client = "btc_price"
method = "get"
url = "https://api.coingecko.com/api/v3/simple/price"
serializer = "price_data"
```
**Usage:**
```bash
# Load single config by name
apiout run --config mempool --json
# Load multiple configs by name
apiout run --config mempool --config btcprice --json
# Use relative/absolute paths
apiout run --config ./local.toml --json
apiout run --config /abs/path/config.toml --json
# Mix config names and paths
apiout run --config mempool --config ./custom.toml --json
```
**XDG Base Directory Support:**
The tool follows the XDG Base Directory specification:
- Uses `$XDG_CONFIG_HOME/apiout/` if set
- Falls back to `~/.config/apiout/` otherwise
See `examples/env_mempool.toml` and `examples/env_btcprice.toml` for complete examples.
### 5. User Parameters
Some APIs require runtime parameters that shouldn't be hardcoded in configuration files.
Use the `-p`/`--param` flag to provide these values:
**Configuration:**
```toml
[clients.mempool]
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
[[apis]]
name = "block_feerates"
client = "mempool"
method = "get_block_feerates"
user_inputs = ["time_period"] # Declare required parameters
```
**Usage:**
```bash
# Single parameter
apiout run -c config.toml -p time_period=24h --json
# Multiple parameters
apiout run -c config.toml -p param1=value1 -p param2=value2 --json
# Combine with config names
apiout run --config mempool -p time_period=1w --json
```
**Features:**
- **Type coercion**: String values are automatically converted to `int` or `float` when
possible (`"42"` → `42`, `"3.14"` → `3.14`)
- **Validation**: APIs with missing required parameters are skipped with a warning
- **Multiple parameters**: Support for APIs requiring multiple user inputs
- **Order matters**: Parameters are passed to methods in the order listed in
`user_inputs`
## CLI Commands
### `run` - Fetch API Data
```bash
# Using config files (by name or path)
apiout run --config <config_name_or_path> [--json]
# Multiple config files
apiout run --config <config1> --config <config2> [--serializers <serializers.toml>] [--json]
# Mix config names and paths
apiout run --config mempool --config ./local.toml [--json]
# OR pipe JSON configuration from stdin
<json-source> | apiout run [--json]
```
**Options:**
- `-c, --config`: Config file to load (can be specified multiple times). Accepts:
- Config name (e.g., `mempool`) → loads from `~/.config/apiout/mempool.toml`
- File path (e.g., `./local.toml` or `/abs/path/config.toml`)
- `-s, --serializers`: Path to serializers configuration file (optional, can be
specified multiple times)
- `-p, --param`: User parameter in format `key=value` (can be specified multiple times)
- `--json`: Output as JSON format (default: pretty-printed)
**Using JSON Input from stdin:**
When JSON is piped to stdin (and `-c` is not provided), apiout automatically detects and
parses it. This is useful for:
- Converting TOML to JSON with tools like `taplo`
- Dynamically generating configurations
- Integration with other tools and scripts
Example with `taplo`:
```bash
taplo get -f examples/mempool_apis.toml -o json | apiout run --json
```
Example with inline JSON:
```bash
echo '{"apis": [{"name": "block_height", "module": "pymempool", "client_class": "MempoolAPI", "method": "get_block_tip_height", "url": "https://mempool.space/api/"}]}' | apiout run --json
```
The JSON format matches the TOML structure:
```json
{
"apis": [
{
"name": "api_name",
"module": "module_name",
"client_class": "Client",
"method": "method_name",
"url": "https://api.url",
"params": {}
}
],
"post_processors": [...],
"serializers": {...}
}
```
### `gen-api` - Generate API Config
Generate an API configuration TOML snippet:
```bash
apiout gen-api \
--module pymempool \
--client-class MempoolAPI \
--client mempool \
--method get_block_tip_hash \
--name block_tip_hash \
--init-params '{"api_base_url": "https://mempool.space/api/"}'
```
**Options:**
- `-m, --module`: Python module name (required)
- `--client-class`: Client class name (default: "Client")
- `--method`: Method name to call (required)
- `-n, --name`: API name (required)
- `--client`: Client reference name (optional: generates `[clients.X]` section)
- `--init-params`: JSON init params dict for client (optional)
- `-u, --url`: API URL (optional)
- `-p, --params`: JSON params dict (optional)
- `--user-inputs`: JSON array of required user input parameter names (optional)
- `--user-defaults`: JSON dict of default values for user inputs (optional)
### `gen-serializer` - Generate Serializer Config
Introspect an API response and generate a serializer configuration from an existing API
config:
```bash
# Generate serializer from API config
apiout gen-serializer --config examples/mempool_apis.toml --api block_tip_hash
# Using config name
apiout gen-serializer --config production --api recommended_fees
# Mix config names and paths
apiout gen-serializer --config mempool --config ./local.toml --api block_tip_hash
```
**Options:**
- `-a, --api`: API name from config (required)
- `-c, --config`: Config file(s) to load (can be specified multiple times). Accepts:
- Config name (e.g., `mempool`) → loads from `~/.config/apiout/mempool.toml`
- File path (e.g., `./local.toml` or `/abs/path/config.toml`)
**How it works:**
1. Loads the config file(s) and finds the API definition by name
2. Extracts all configuration details (module, client, method, url, params, init_params)
3. Makes an actual API call using the configured client
4. Introspects the response structure
5. Generates a serializer TOML configuration
**Example:**
Given a config file `mempool.toml`:
```toml
[clients.mempool]
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
[[apis]]
name = "block_tip_hash"
client = "mempool"
method = "get_block_tip_hash"
```
Running:
```bash
apiout gen-serializer --config mempool.toml --api block_tip_hash
```
Outputs:
```toml
[serializers.block_tip_hash_serializer]
[serializers.block_tip_hash_serializer.fields]
hash = "hash_value"
```
## Configuration Format
### API Configuration
```toml
[[apis]]
name = "api_name" # Unique identifier for this API
module = "module_name" # Python module to import
client_class = "Client" # Class name (default: "Client")
method = "method_name" # Method to call on the client
url = "https://api.url" # API endpoint URL
serializer = "serializer_ref" # Reference to serializer (optional)
[apis.params] # Parameters to pass to the method
key = "value"
```
### Serializer Configuration
```toml
[serializers.name]
[serializers.name.fields]
output_field = "InputAttribute" # Map output field to object attribute
[serializers.name.fields.nested]
method = "MethodName" # Call a method on the object
[serializers.name.fields.nested.fields]
nested_field = "NestedAttribute"
[serializers.name.fields.collection]
iterate = {
count = "CountMethod",
item = "ItemMethod",
fields = { value = "Value" }
}
```
## Advanced Serializer Features
### Client-Scoped Serializers
When working with multiple clients, you can scope serializers to specific clients to
avoid namespace collisions:
```toml
# Define clients
[clients.btc_price]
module = "requests"
client_class = "Session"
[clients.mempool]
module = "pymempool"
client_class = "MempoolAPI"
# Global serializers (backward compatible)
[serializers.generic_data]
[serializers.generic_data.fields]
value = "data"
# Client-scoped serializers - nested under client names
[serializers.btc_price.price_data]
[serializers.btc_price.price_data.fields]
usd = "usd_price"
eur = "eur_price"
[serializers.mempool.price_data]
[serializers.mempool.price_data.fields]
sats_per_dollar = "price"
timestamp = "time"
# APIs automatically resolve serializers in client scope
[[apis]]
name = "btc_price"
client = "btc_price"
method = "get"
url = "https://api.example.com"
serializer = "price_data" # Resolves to btc_price.price_data
[[apis]]
name = "mempool_price"
client = "mempool"
method = "get_price"
url = "https://mempool.space/api/"
serializer = "price_data" # Resolves to mempool.price_data
```
**Resolution Order:**
1. Inline dict (highest priority)
2. Explicit dotted reference (e.g., `"client_name.serializer"`)
3. Client-scoped lookup (e.g., when API has `client = "foo"` and `serializer = "bar"`)
4. Global lookup (backward compatible)
See `examples/scoped_serializers_example.toml` for a complete example.
### Method Calls
Call methods on objects:
```toml
[serializers.example.fields.data]
method = "GetData"
[serializers.example.fields.data.fields]
value = "Value"
```
### Iteration
Iterate over collections:
```toml
[serializers.example.fields.items]
method = "GetContainer"
[serializers.example.fields.items.fields.variables]
iterate = {
count = "Length", # Method that returns count
item = "GetItem", # Method that takes index and returns item
fields = {
name = "Name", # Fields to extract from each item
value = "Value"
}
}
```
### NumPy Array Support
The serializer automatically converts NumPy arrays to lists:
```toml
[serializers.example.fields.data]
values = "ValuesAsNumpy" # Returns numpy array, auto-converted to list
```
## Post-Processors
Post-processors allow you to combine and transform data from multiple API calls into a
single result. This is useful when you need to:
- Aggregate data from multiple endpoints
- Perform calculations using multiple API responses
- Create custom data structures from API results
### Configuration Format
```toml
[[post_processors]]
name = "processor_name" # Unique identifier
module = "module_name" # Python module containing the processor
class = "ProcessorClass" # Class to instantiate
method = "process" # Optional: method to call (default: use __init__)
inputs = ["api1", "api2"] # List of API result names to pass as inputs
serializer = "serializer_ref" # Optional: serializer for the output
```
### How It Works
1. All APIs defined in `[[apis]]` sections are fetched first
2. Post-processors are executed in order, receiving API results as inputs
3. Each post-processor's result is added to the results dictionary
4. Later post-processors can use outputs from earlier post-processors
### Example: Combining Mempool Data
This example uses the `pymempool` library's built-in `RecommendedFees` class as a
post-processor:
```toml
# Define the APIs
[[apis]]
name = "recommended_fees"
module = "pymempool"
client_class = "MempoolAPI"
method = "get_recommended_fees"
url = "https://mempool.space/api/"
[[apis]]
name = "mempool_blocks_fee"
module = "pymempool"
client_class = "MempoolAPI"
method = "get_mempool_blocks_fee"
url = "https://mempool.space/api/"
# Define the post-processor using pymempool's RecommendedFees class
[[post_processors]]
name = "fee_analysis"
module = "pymempool"
class = "RecommendedFees"
inputs = ["recommended_fees", "mempool_blocks_fee"]
serializer = "fee_analysis_serializer"
```
Define the serializer for the post-processor output:
```toml
[serializers.fee_analysis_serializer]
[serializers.fee_analysis_serializer.fields]
fastest_fee = "fastest_fee"
half_hour_fee = "half_hour_fee"
hour_fee = "hour_fee"
mempool_tx_count = "mempool_tx_count"
mempool_vsize = "mempool_vsize"
mempool_blocks = "mempool_blocks"
```
Run it:
```bash
apiout run --config mempool_apis.toml --serializers mempool_serializers.toml --json
```
The output will include the `fee_analysis` result with all combined data from both APIs.
## Examples
See the included `myapi.toml` for a complete example with the OpenMeteo API, or check
the separate `apis.toml` and `serializers.toml` files for the split configuration
approach.
## Development
### Running Tests
```bash
pytest tests/ -v
```
### Coverage
```bash
pytest tests/ --cov=apiout --cov-report=html
```
## License
MIT
Raw data
{
"_id": null,
"home_page": null,
"name": "apiout",
"maintainer": null,
"docs_url": null,
"requires_python": ">3.8.0",
"maintainer_email": null,
"keywords": "api, json, toml, serialization, cli, http, rest",
"author": null,
"author_email": "Holger Nahrstaedt <nahrstaedt@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/c2/14/cf1de1c863c87e26623770f668964c4235a5b3e769ad61776653fb67aa82/apiout-0.6.0.tar.gz",
"platform": null,
"description": "[](https://pypi.org/project/apiout/)\n\n\n[](https://codecov.io/gh/holgern/apiout)\n\n# apiout\n\nA flexible Python tool for fetching data from APIs and serializing responses using TOML\nconfiguration files.\n\n## Features\n\n- **Config-driven API calls**: Define API endpoints, parameters, and authentication in\n TOML files\n- **Flexible serialization**: Map API responses to desired output formats using\n configurable field mappings\n- **Separate concerns**: Keep API configurations and serializers in separate files for\n better organization\n- **Default serialization**: Works without serializers - automatically converts objects\n to dictionaries\n- **Generator tool**: Introspect API responses and auto-generate serializer\n configurations\n\n## Installation\n\n```bash\npip install -e .\n```\n\n## Quick Start\n\n### 1. Basic Usage (No Serializers)\n\nCreate an API configuration file (`apis.toml`):\n\n```toml\n[[apis]]\nname = \"berlin_weather\"\nmodule = \"openmeteo_requests\"\nclient_class = \"Client\"\nmethod = \"weather_api\"\nurl = \"https://api.open-meteo.com/v1/forecast\"\n\n[apis.params]\nlatitude = 52.52\nlongitude = 13.41\ncurrent = [\"temperature_2m\"]\n```\n\nRun the API fetcher:\n\n```bash\napiout run -c apis.toml --json\n```\n\nWithout serializers, the tool will automatically convert the response objects to\ndictionaries.\n\n### 2. Using Serializers\n\nCreate a serializer configuration file (`serializers.toml`):\n\n```toml\n[serializers.openmeteo]\n[serializers.openmeteo.fields]\nlatitude = \"Latitude\"\nlongitude = \"Longitude\"\ntimezone = \"Timezone\"\n\n[serializers.openmeteo.fields.current]\nmethod = \"Current\"\n[serializers.openmeteo.fields.current.fields]\ntime = \"Time\"\ntemperature = \"Temperature\"\n```\n\nUpdate your API configuration to reference the serializer:\n\n```toml\n[[apis]]\nname = \"berlin_weather\"\nmodule = \"openmeteo_requests\"\nclient_class = \"Client\"\nmethod = \"weather_api\"\nurl = \"https://api.open-meteo.com/v1/forecast\"\nserializer = \"openmeteo\" # Reference the serializer\n\n[apis.params]\nlatitude = 52.52\nlongitude = 13.41\ncurrent = [\"temperature_2m\"]\n```\n\nRun with both configurations:\n\n```bash\napiout run --config apis.toml --serializers serializers.toml --json\n```\n\n### 3. Inline Serializers\n\nYou can also define serializers inline in the API configuration:\n\n```toml\n[serializers.openmeteo]\n[serializers.openmeteo.fields]\nlatitude = \"Latitude\"\nlongitude = \"Longitude\"\n\n[[apis]]\nname = \"berlin_weather\"\nmodule = \"openmeteo_requests\"\nmethod = \"weather_api\"\nurl = \"https://api.open-meteo.com/v1/forecast\"\nserializer = \"openmeteo\"\n```\n\nRun with just the API config:\n\n```bash\napiout run -c apis.toml --json\n```\n\n### 4. Config Directory\n\nFor cleaner configuration management, you can store reusable API configurations in\n`~/.config/apiout/` and load them by name using the `--config` flag:\n\n**Setup:**\n\nCreate config files in `~/.config/apiout/`:\n\n```bash\n# ~/.config/apiout/mempool.toml\n[clients.mempool]\nmodule = \"requests\"\nclient_class = \"Session\"\n\n[serializers.mempool.block_data]\n[serializers.mempool.block_data.fields]\nhash = \"id\"\nheight = \"height\"\ntimestamp = \"timestamp\"\n\n[[apis]]\nname = \"mempool_blocks\"\nclient = \"mempool\"\nmethod = \"get\"\nurl = \"https://mempool.space/api/v1/blocks\"\nserializer = \"block_data\"\n```\n\n```bash\n# ~/.config/apiout/btcprice.toml\n[clients.btc_price]\nmodule = \"requests\"\nclient_class = \"Session\"\n\n[serializers.btc_price.price_data]\n[serializers.btc_price.price_data.fields]\nusd = \"bitcoin.usd\"\neur = \"bitcoin.eur\"\n\n[[apis]]\nname = \"btc_price\"\nclient = \"btc_price\"\nmethod = \"get\"\nurl = \"https://api.coingecko.com/api/v3/simple/price\"\nserializer = \"price_data\"\n```\n\n**Usage:**\n\n```bash\n# Load single config by name\napiout run --config mempool --json\n\n# Load multiple configs by name\napiout run --config mempool --config btcprice --json\n\n# Use relative/absolute paths\napiout run --config ./local.toml --json\napiout run --config /abs/path/config.toml --json\n\n# Mix config names and paths\napiout run --config mempool --config ./custom.toml --json\n```\n\n**XDG Base Directory Support:**\n\nThe tool follows the XDG Base Directory specification:\n\n- Uses `$XDG_CONFIG_HOME/apiout/` if set\n- Falls back to `~/.config/apiout/` otherwise\n\nSee `examples/env_mempool.toml` and `examples/env_btcprice.toml` for complete examples.\n\n### 5. User Parameters\n\nSome APIs require runtime parameters that shouldn't be hardcoded in configuration files.\nUse the `-p`/`--param` flag to provide these values:\n\n**Configuration:**\n\n```toml\n[clients.mempool]\nmodule = \"pymempool\"\nclient_class = \"MempoolAPI\"\ninit_params = {api_base_url = \"https://mempool.space/api/\"}\n\n[[apis]]\nname = \"block_feerates\"\nclient = \"mempool\"\nmethod = \"get_block_feerates\"\nuser_inputs = [\"time_period\"] # Declare required parameters\n```\n\n**Usage:**\n\n```bash\n# Single parameter\napiout run -c config.toml -p time_period=24h --json\n\n# Multiple parameters\napiout run -c config.toml -p param1=value1 -p param2=value2 --json\n\n# Combine with config names\napiout run --config mempool -p time_period=1w --json\n```\n\n**Features:**\n\n- **Type coercion**: String values are automatically converted to `int` or `float` when\n possible (`\"42\"` \u2192 `42`, `\"3.14\"` \u2192 `3.14`)\n- **Validation**: APIs with missing required parameters are skipped with a warning\n- **Multiple parameters**: Support for APIs requiring multiple user inputs\n- **Order matters**: Parameters are passed to methods in the order listed in\n `user_inputs`\n\n## CLI Commands\n\n### `run` - Fetch API Data\n\n```bash\n# Using config files (by name or path)\napiout run --config <config_name_or_path> [--json]\n\n# Multiple config files\napiout run --config <config1> --config <config2> [--serializers <serializers.toml>] [--json]\n\n# Mix config names and paths\napiout run --config mempool --config ./local.toml [--json]\n\n# OR pipe JSON configuration from stdin\n<json-source> | apiout run [--json]\n```\n\n**Options:**\n\n- `-c, --config`: Config file to load (can be specified multiple times). Accepts:\n - Config name (e.g., `mempool`) \u2192 loads from `~/.config/apiout/mempool.toml`\n - File path (e.g., `./local.toml` or `/abs/path/config.toml`)\n- `-s, --serializers`: Path to serializers configuration file (optional, can be\n specified multiple times)\n- `-p, --param`: User parameter in format `key=value` (can be specified multiple times)\n- `--json`: Output as JSON format (default: pretty-printed)\n\n**Using JSON Input from stdin:**\n\nWhen JSON is piped to stdin (and `-c` is not provided), apiout automatically detects and\nparses it. This is useful for:\n\n- Converting TOML to JSON with tools like `taplo`\n- Dynamically generating configurations\n- Integration with other tools and scripts\n\nExample with `taplo`:\n\n```bash\ntaplo get -f examples/mempool_apis.toml -o json | apiout run --json\n```\n\nExample with inline JSON:\n\n```bash\necho '{\"apis\": [{\"name\": \"block_height\", \"module\": \"pymempool\", \"client_class\": \"MempoolAPI\", \"method\": \"get_block_tip_height\", \"url\": \"https://mempool.space/api/\"}]}' | apiout run --json\n```\n\nThe JSON format matches the TOML structure:\n\n```json\n{\n \"apis\": [\n {\n \"name\": \"api_name\",\n \"module\": \"module_name\",\n \"client_class\": \"Client\",\n \"method\": \"method_name\",\n \"url\": \"https://api.url\",\n \"params\": {}\n }\n ],\n \"post_processors\": [...],\n \"serializers\": {...}\n}\n```\n\n### `gen-api` - Generate API Config\n\nGenerate an API configuration TOML snippet:\n\n```bash\napiout gen-api \\\n --module pymempool \\\n --client-class MempoolAPI \\\n --client mempool \\\n --method get_block_tip_hash \\\n --name block_tip_hash \\\n --init-params '{\"api_base_url\": \"https://mempool.space/api/\"}'\n```\n\n**Options:**\n\n- `-m, --module`: Python module name (required)\n- `--client-class`: Client class name (default: \"Client\")\n- `--method`: Method name to call (required)\n- `-n, --name`: API name (required)\n- `--client`: Client reference name (optional: generates `[clients.X]` section)\n- `--init-params`: JSON init params dict for client (optional)\n- `-u, --url`: API URL (optional)\n- `-p, --params`: JSON params dict (optional)\n- `--user-inputs`: JSON array of required user input parameter names (optional)\n- `--user-defaults`: JSON dict of default values for user inputs (optional)\n\n### `gen-serializer` - Generate Serializer Config\n\nIntrospect an API response and generate a serializer configuration from an existing API\nconfig:\n\n```bash\n# Generate serializer from API config\napiout gen-serializer --config examples/mempool_apis.toml --api block_tip_hash\n\n# Using config name\napiout gen-serializer --config production --api recommended_fees\n\n# Mix config names and paths\napiout gen-serializer --config mempool --config ./local.toml --api block_tip_hash\n```\n\n**Options:**\n\n- `-a, --api`: API name from config (required)\n- `-c, --config`: Config file(s) to load (can be specified multiple times). Accepts:\n - Config name (e.g., `mempool`) \u2192 loads from `~/.config/apiout/mempool.toml`\n - File path (e.g., `./local.toml` or `/abs/path/config.toml`)\n\n**How it works:**\n\n1. Loads the config file(s) and finds the API definition by name\n2. Extracts all configuration details (module, client, method, url, params, init_params)\n3. Makes an actual API call using the configured client\n4. Introspects the response structure\n5. Generates a serializer TOML configuration\n\n**Example:**\n\nGiven a config file `mempool.toml`:\n\n```toml\n[clients.mempool]\nmodule = \"pymempool\"\nclient_class = \"MempoolAPI\"\ninit_params = {api_base_url = \"https://mempool.space/api/\"}\n\n[[apis]]\nname = \"block_tip_hash\"\nclient = \"mempool\"\nmethod = \"get_block_tip_hash\"\n```\n\nRunning:\n\n```bash\napiout gen-serializer --config mempool.toml --api block_tip_hash\n```\n\nOutputs:\n\n```toml\n[serializers.block_tip_hash_serializer]\n[serializers.block_tip_hash_serializer.fields]\nhash = \"hash_value\"\n```\n\n## Configuration Format\n\n### API Configuration\n\n```toml\n[[apis]]\nname = \"api_name\" # Unique identifier for this API\nmodule = \"module_name\" # Python module to import\nclient_class = \"Client\" # Class name (default: \"Client\")\nmethod = \"method_name\" # Method to call on the client\nurl = \"https://api.url\" # API endpoint URL\nserializer = \"serializer_ref\" # Reference to serializer (optional)\n\n[apis.params] # Parameters to pass to the method\nkey = \"value\"\n```\n\n### Serializer Configuration\n\n```toml\n[serializers.name]\n[serializers.name.fields]\noutput_field = \"InputAttribute\" # Map output field to object attribute\n\n[serializers.name.fields.nested]\nmethod = \"MethodName\" # Call a method on the object\n[serializers.name.fields.nested.fields]\nnested_field = \"NestedAttribute\"\n\n[serializers.name.fields.collection]\niterate = {\n count = \"CountMethod\",\n item = \"ItemMethod\",\n fields = { value = \"Value\" }\n}\n```\n\n## Advanced Serializer Features\n\n### Client-Scoped Serializers\n\nWhen working with multiple clients, you can scope serializers to specific clients to\navoid namespace collisions:\n\n```toml\n# Define clients\n[clients.btc_price]\nmodule = \"requests\"\nclient_class = \"Session\"\n\n[clients.mempool]\nmodule = \"pymempool\"\nclient_class = \"MempoolAPI\"\n\n# Global serializers (backward compatible)\n[serializers.generic_data]\n[serializers.generic_data.fields]\nvalue = \"data\"\n\n# Client-scoped serializers - nested under client names\n[serializers.btc_price.price_data]\n[serializers.btc_price.price_data.fields]\nusd = \"usd_price\"\neur = \"eur_price\"\n\n[serializers.mempool.price_data]\n[serializers.mempool.price_data.fields]\nsats_per_dollar = \"price\"\ntimestamp = \"time\"\n\n# APIs automatically resolve serializers in client scope\n[[apis]]\nname = \"btc_price\"\nclient = \"btc_price\"\nmethod = \"get\"\nurl = \"https://api.example.com\"\nserializer = \"price_data\" # Resolves to btc_price.price_data\n\n[[apis]]\nname = \"mempool_price\"\nclient = \"mempool\"\nmethod = \"get_price\"\nurl = \"https://mempool.space/api/\"\nserializer = \"price_data\" # Resolves to mempool.price_data\n```\n\n**Resolution Order:**\n\n1. Inline dict (highest priority)\n2. Explicit dotted reference (e.g., `\"client_name.serializer\"`)\n3. Client-scoped lookup (e.g., when API has `client = \"foo\"` and `serializer = \"bar\"`)\n4. Global lookup (backward compatible)\n\nSee `examples/scoped_serializers_example.toml` for a complete example.\n\n### Method Calls\n\nCall methods on objects:\n\n```toml\n[serializers.example.fields.data]\nmethod = \"GetData\"\n[serializers.example.fields.data.fields]\nvalue = \"Value\"\n```\n\n### Iteration\n\nIterate over collections:\n\n```toml\n[serializers.example.fields.items]\nmethod = \"GetContainer\"\n[serializers.example.fields.items.fields.variables]\niterate = {\n count = \"Length\", # Method that returns count\n item = \"GetItem\", # Method that takes index and returns item\n fields = {\n name = \"Name\", # Fields to extract from each item\n value = \"Value\"\n }\n}\n```\n\n### NumPy Array Support\n\nThe serializer automatically converts NumPy arrays to lists:\n\n```toml\n[serializers.example.fields.data]\nvalues = \"ValuesAsNumpy\" # Returns numpy array, auto-converted to list\n```\n\n## Post-Processors\n\nPost-processors allow you to combine and transform data from multiple API calls into a\nsingle result. This is useful when you need to:\n\n- Aggregate data from multiple endpoints\n- Perform calculations using multiple API responses\n- Create custom data structures from API results\n\n### Configuration Format\n\n```toml\n[[post_processors]]\nname = \"processor_name\" # Unique identifier\nmodule = \"module_name\" # Python module containing the processor\nclass = \"ProcessorClass\" # Class to instantiate\nmethod = \"process\" # Optional: method to call (default: use __init__)\ninputs = [\"api1\", \"api2\"] # List of API result names to pass as inputs\nserializer = \"serializer_ref\" # Optional: serializer for the output\n```\n\n### How It Works\n\n1. All APIs defined in `[[apis]]` sections are fetched first\n2. Post-processors are executed in order, receiving API results as inputs\n3. Each post-processor's result is added to the results dictionary\n4. Later post-processors can use outputs from earlier post-processors\n\n### Example: Combining Mempool Data\n\nThis example uses the `pymempool` library's built-in `RecommendedFees` class as a\npost-processor:\n\n```toml\n# Define the APIs\n[[apis]]\nname = \"recommended_fees\"\nmodule = \"pymempool\"\nclient_class = \"MempoolAPI\"\nmethod = \"get_recommended_fees\"\nurl = \"https://mempool.space/api/\"\n\n[[apis]]\nname = \"mempool_blocks_fee\"\nmodule = \"pymempool\"\nclient_class = \"MempoolAPI\"\nmethod = \"get_mempool_blocks_fee\"\nurl = \"https://mempool.space/api/\"\n\n# Define the post-processor using pymempool's RecommendedFees class\n[[post_processors]]\nname = \"fee_analysis\"\nmodule = \"pymempool\"\nclass = \"RecommendedFees\"\ninputs = [\"recommended_fees\", \"mempool_blocks_fee\"]\nserializer = \"fee_analysis_serializer\"\n```\n\nDefine the serializer for the post-processor output:\n\n```toml\n[serializers.fee_analysis_serializer]\n[serializers.fee_analysis_serializer.fields]\nfastest_fee = \"fastest_fee\"\nhalf_hour_fee = \"half_hour_fee\"\nhour_fee = \"hour_fee\"\nmempool_tx_count = \"mempool_tx_count\"\nmempool_vsize = \"mempool_vsize\"\nmempool_blocks = \"mempool_blocks\"\n```\n\nRun it:\n\n```bash\napiout run --config mempool_apis.toml --serializers mempool_serializers.toml --json\n```\n\nThe output will include the `fee_analysis` result with all combined data from both APIs.\n\n## Examples\n\nSee the included `myapi.toml` for a complete example with the OpenMeteo API, or check\nthe separate `apis.toml` and `serializers.toml` files for the split configuration\napproach.\n\n## Development\n\n### Running Tests\n\n```bash\npytest tests/ -v\n```\n\n### Coverage\n\n```bash\npytest tests/ --cov=apiout --cov-report=html\n```\n\n## License\n\nMIT\n",
"bugtrack_url": null,
"license": "MIT License\n \n Copyright (c) 2025 Holger\n \n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n \n The above copyright notice and this permission notice shall be included in all\n copies or substantial portions of the Software.\n \n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n SOFTWARE.\n ",
"summary": "A flexible Python tool for fetching data from APIs and serializing responses using TOML configuration files",
"version": "0.6.0",
"project_urls": {
"Homepage": "https://github.com/holgern/apiout"
},
"split_keywords": [
"api",
" json",
" toml",
" serialization",
" cli",
" http",
" rest"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "426520f82c9c7357ff95066d51fc6f12a6e91ac0347f8fe0fa7c688c1a1c445d",
"md5": "e2802a5dcdfc56d4e4effe1affc54f18",
"sha256": "d7c10b9d9b919f4fcccb362b40d725794a70e22cc75ebc588175fe0714f4e06c"
},
"downloads": -1,
"filename": "apiout-0.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e2802a5dcdfc56d4e4effe1affc54f18",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">3.8.0",
"size": 26740,
"upload_time": "2025-10-24T09:34:40",
"upload_time_iso_8601": "2025-10-24T09:34:40.504933Z",
"url": "https://files.pythonhosted.org/packages/42/65/20f82c9c7357ff95066d51fc6f12a6e91ac0347f8fe0fa7c688c1a1c445d/apiout-0.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c214cf1de1c863c87e26623770f668964c4235a5b3e769ad61776653fb67aa82",
"md5": "aedd4236eee8b0d36157786668645a1c",
"sha256": "74fd9cce8221135917b95302d152d9a7d9490e90cf9e88eb47e60b06e24b859a"
},
"downloads": -1,
"filename": "apiout-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "aedd4236eee8b0d36157786668645a1c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">3.8.0",
"size": 78401,
"upload_time": "2025-10-24T09:34:41",
"upload_time_iso_8601": "2025-10-24T09:34:41.341242Z",
"url": "https://files.pythonhosted.org/packages/c2/14/cf1de1c863c87e26623770f668964c4235a5b3e769ad61776653fb67aa82/apiout-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-24 09:34:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "holgern",
"github_project": "apiout",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"requirements": [],
"lcname": "apiout"
}