Examples
This page provides practical examples of using apiout for various use cases.
Weather API Example
OpenMeteo API Integration
Fetch weather data from the OpenMeteo API with full serialization.
Configuration Files
apis.toml:
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
client_class = "Client"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
[apis.params]
latitude = 52.52
longitude = 13.41
hourly = ["temperature_2m", "precipitation", "wind_speed_10m"]
current = ["temperature_2m", "relative_humidity_2m"]
serializers.toml:
[serializers.openmeteo]
[serializers.openmeteo.fields]
latitude = "Latitude"
longitude = "Longitude"
elevation = "Elevation"
timezone = "Timezone"
timezone_abbreviation = "TimezoneAbbreviation"
utc_offset_seconds = "UtcOffsetSeconds"
[serializers.openmeteo.fields.current]
method = "Current"
[serializers.openmeteo.fields.current.fields]
time = "Time"
[serializers.openmeteo.fields.current.fields.variables]
iterate = {
count = "VariablesLength",
item = "Variables",
fields = { value = "Value" }
}
[serializers.openmeteo.fields.hourly]
method = "Hourly"
[serializers.openmeteo.fields.hourly.fields]
time = "Time"
time_end = "TimeEnd"
interval = "Interval"
[serializers.openmeteo.fields.hourly.fields.variables]
iterate = {
count = "VariablesLength",
item = "Variables",
fields = { values = "ValuesAsNumpy" }
}
Running the Example
apiout run --config examples/apis.toml --serializers examples/serializers.toml --json
Expected Output
{
"berlin_weather": [
{
"latitude": 52.52,
"longitude": 13.41,
"elevation": 38.0,
"timezone": "GMT",
"timezone_abbreviation": "GMT",
"utc_offset_seconds": 0,
"current": {
"time": 1760711400,
"variables": [
{"value": 12.15},
{"value": 59.0}
]
},
"hourly": {
"time": 1760659200,
"time_end": 1761264000,
"interval": 3600,
"variables": [
{"values": [11.5, 11.1, 11.0, ...]},
{"values": [0.0, 0.0, 0.0, ...]},
{"values": [12.3, 11.8, 10.5, ...]}
]
}
}
]
}
Multiple Cities
Fetch weather for multiple cities in one configuration:
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
client_class = "Client"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
[apis.params]
latitude = 52.52
longitude = 13.41
current = ["temperature_2m"]
[[apis]]
name = "munich_weather"
module = "openmeteo_requests"
client_class = "Client"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
[apis.params]
latitude = 48.1351
longitude = 11.5820
current = ["temperature_2m"]
Default Serialization Example
Testing Without Serializers
When exploring a new API, start without serializers to see the raw structure:
[[apis]]
name = "test_api"
module = "requests"
client_class = "Session"
method = "get"
url = "https://api.example.com/data"
Run without serializer config:
apiout run --config config.toml --json
apiout will automatically convert objects to dictionaries, showing all public attributes.
Generator Example
Auto-Generate Serializer Config
Use the generator to create an initial serializer configuration:
apiout generate \
--module openmeteo_requests \
--client-class Client \
--method weather_api \
--url "https://api.open-meteo.com/v1/forecast" \
--params '{"latitude": 52.52, "longitude": 13.41, "current": ["temperature_2m"]}' \
--name openmeteo > serializers.toml
This introspects the API response and generates a TOML config you can refine.
Nested Objects Example
Complex Data Structures
Handle deeply nested API responses:
[serializers.complex]
[serializers.complex.fields]
id = "Id"
name = "Name"
[serializers.complex.fields.metadata]
method = "GetMetadata"
[serializers.complex.fields.metadata.fields]
created = "CreatedAt"
updated = "UpdatedAt"
[serializers.complex.fields.metadata.fields.author]
method = "GetAuthor"
[serializers.complex.fields.metadata.fields.author.fields]
name = "Name"
email = "Email"
This creates a structure like:
{
"id": 123,
"name": "Example",
"metadata": {
"created": "2025-01-01",
"updated": "2025-01-15",
"author": {
"name": "John Doe",
"email": "john@example.com"
}
}
}
Collection Iteration Example
Processing Lists of Items
Iterate over collections of objects:
[serializers.collection]
[serializers.collection.fields]
total = "TotalCount"
[serializers.collection.fields.items]
iterate = {
count = "ItemCount",
item = "GetItem",
fields = {
id = "Id",
name = "Name",
price = "Price"
}
}
Result:
{
"total": 10,
"items": [
{"id": 1, "name": "Item 1", "price": 9.99},
{"id": 2, "name": "Item 2", "price": 19.99},
...
]
}
Inline Serializer Example
Single-File Configuration
For small projects, keep everything in one file:
[serializers.simple]
[serializers.simple.fields]
value = "Value"
timestamp = "Timestamp"
[[apis]]
name = "simple_api"
module = "my_module"
client_class = "Client"
method = "fetch_data"
url = "https://api.example.com"
serializer = "simple"
[apis.params]
key = "value"
Run with just the config file:
apiout run --config config.toml --json
Python Integration Example
Using apiout Programmatically
from apiout.fetcher import fetch_api_data
api_config = {
"name": "test_api",
"module": "openmeteo_requests",
"client_class": "Client",
"method": "weather_api",
"url": "https://api.open-meteo.com/v1/forecast",
"params": {
"latitude": 52.52,
"longitude": 13.41,
"current": ["temperature_2m"]
}
}
result = fetch_api_data(api_config)
print(result)
With Custom Serializer
from apiout.fetcher import fetch_api_data
api_config = {
"name": "test_api",
"module": "openmeteo_requests",
"method": "weather_api",
"url": "https://api.open-meteo.com/v1/forecast",
"serializer": "openmeteo",
"params": {"latitude": 52.52, "longitude": 13.41}
}
serializers = {
"openmeteo": {
"fields": {
"latitude": "Latitude",
"longitude": "Longitude"
}
}
}
result = fetch_api_data(api_config, serializers)
print(result)
Reusable Client Configurations Example
Eliminating Configuration Repetition
When multiple APIs use the same client, define it once and reference it multiple times.
Without Client References (repetitive):
[[apis]]
name = "block_tip_hash"
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
method = "get_block_tip_hash"
[[apis]]
name = "block_tip_height"
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
method = "get_block_tip_height"
With Client References (clean and maintainable):
mempool_apis.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"
[[apis]]
name = "block_tip_height"
client = "mempool"
method = "get_block_tip_height"
[[apis]]
name = "recommended_fees"
client = "mempool"
method = "get_recommended_fees"
[[apis]]
name = "difficulty_adjustment"
client = "mempool"
method = "get_difficulty_adjustment"
Running the Example
pip install pymempool
apiout run --config mempool_apis.toml --json
How It Works
The
[clients.mempool]section defines the client configuration onceEach API references
client = "mempool"instead of repeating initializationAll APIs share the same client instance automatically
Changing the API URL only requires updating one line
Benefits
Define client configuration once, use it many times
Update client settings in one place
Cleaner, more maintainable configurations
Automatic instance sharing across referenced APIs
With Init Method
For clients that require initialization, define init_method in the client configuration:
btcpriceticker.toml:
[clients.btc_price]
module = "btcpriceticker"
client_class = "Price"
init_params = {fiat = "EUR", days_ago = 1, service = "coinpaprika"}
init_method = "update_service"
[[apis]]
name = "btc_price_usd"
client = "btc_price"
method = "get_usd_price"
[[apis]]
name = "btc_price_eur"
client = "btc_price"
method = "get_fiat_price"
[[apis]]
name = "btc_price_timestamp"
client = "btc_price"
method = "get_timestamp"
Running the Example
pip install btcpriceticker
apiout run --config btcpriceticker.toml --json
How It Works
The client is defined once with
init_method = "update_service"When first referenced, the client is instantiated and
update_service()is calledAll subsequent APIs reuse the same instance without re-initialization
Data is fetched once, queried multiple times
Expected Output
{
"btc_price_usd": 109315.67,
"btc_price_eur": 93970.49,
"btc_price_timestamp": 1761049894.21
}
Multiple Configuration Files Example
Organizing Large Projects
For large projects, split configurations into multiple files:
Base Configuration (base.toml):
[serializers.common]
[serializers.common.fields]
timestamp = "Timestamp"
status = "Status"
API Configurations (weather_apis.toml):
[[apis]]
name = "berlin_weather"
module = "openmeteo_requests"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
[apis.params]
latitude = 52.52
longitude = 13.41
current = ["temperature_2m"]
Additional APIs (more_apis.toml):
[[apis]]
name = "munich_weather"
module = "openmeteo_requests"
method = "weather_api"
url = "https://api.open-meteo.com/v1/forecast"
serializer = "openmeteo"
[apis.params]
latitude = 48.1351
longitude = 11.5820
current = ["temperature_2m"]
Custom Serializers (custom_serializers.toml):
[serializers.openmeteo]
[serializers.openmeteo.fields]
latitude = "Latitude"
longitude = "Longitude"
Running the Example
apiout run --config base.toml --config weather_apis.toml --config more_apis.toml --serializers custom_serializers.toml --json
How It Works
Config files are merged in order: base → weather_apis → more_apis
All APIs are collected:
berlin_weather,munich_weatherSerializers from
custom_serializers.tomloverride any with the same name frombase.tomlAPIs are executed and serialized
Benefits
Organize related APIs together
Share common configurations across projects
Override serializers for different environments
Keep configurations maintainable and modular
Pipeline Integration Example
Using in Data Pipelines
Integrate apiout into data processing pipelines:
# Fetch data and pipe to jq for filtering
apiout run --config config.toml --json | jq '.berlin_weather[0].current'
# Save to file
apiout run --config config.toml --json > weather_data.json
# Pipe to Python for processing
apiout run --config config.toml --json | python process_weather.py
Combining Multiple APIs
# Run multiple configs and merge results
{
echo "{"
apiout run --config weather.toml --json | jq -r '.berlin_weather'
echo ","
apiout run --config stocks.toml --json | jq -r '.stock_data'
echo "}"
} | jq -s '.[0]'
Reusable Client Configurations Example
Eliminating Configuration Repetition
When multiple APIs use the same client, define it once and reference it multiple times.
Without Client References (repetitive):
[[apis]]
name = "block_tip_hash"
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
method = "get_block_tip_hash"
[[apis]]
name = "block_tip_height"
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
method = "get_block_tip_height"
With Client References (clean and maintainable):
mempool_apis.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"
[[apis]]
name = "block_tip_height"
client = "mempool"
method = "get_block_tip_height"
[[apis]]
name = "recommended_fees"
client = "mempool"
method = "get_recommended_fees"
[[apis]]
name = "difficulty_adjustment"
client = "mempool"
method = "get_difficulty_adjustment"
Running the Example
pip install pymempool
apiout run --config mempool_apis.toml --json
How It Works
The
[clients.mempool]section defines the client configuration onceEach API references
client = "mempool"instead of repeating initializationAll APIs share the same client instance automatically
Changing the API URL only requires updating one line
Benefits
Define client configuration once, use it many times
Update client settings in one place
Cleaner, more maintainable configurations
Automatic instance sharing across referenced APIs
With Init Method
For clients that require initialization, define init_method in the client configuration:
btcpriceticker.toml:
[clients.btc_price]
module = "btcpriceticker"
client_class = "Price"
init_params = {fiat = "EUR", days_ago = 1, service = "coinpaprika"}
init_method = "update_service"
[[apis]]
name = "btc_price_usd"
client = "btc_price"
method = "get_usd_price"
[[apis]]
name = "btc_price_eur"
client = "btc_price"
method = "get_fiat_price"
[[apis]]
name = "btc_price_timestamp"
client = "btc_price"
method = "get_timestamp"
Running the Example
pip install btcpriceticker
apiout run --config btcpriceticker.toml --json
How It Works
The client is defined once with
init_method = "update_service"When first referenced, the client is instantiated and
update_service()is calledAll subsequent APIs reuse the same instance without re-initialization
Data is fetched once, queried multiple times
Expected Output
{
"btc_price_usd": 109315.67,
"btc_price_eur": 93970.49,
"btc_price_timestamp": 1761049894.21
}
Post-Processor Example
Combining Multiple API Results
Post-processors allow you to combine and transform data from multiple API calls using any Python class. They can also use client references for cleaner configuration.
Configuration
mempool_apis.toml:
[clients.mempool]
module = "pymempool"
client_class = "MempoolAPI"
init_params = {api_base_url = "https://mempool.space/api/"}
[[apis]]
name = "recommended_fees"
client = "mempool"
method = "get_recommended_fees"
[[apis]]
name = "mempool_blocks_fee"
client = "mempool"
method = "get_mempool_blocks_fee"
[[post_processors]]
name = "fee_analysis"
client = "mempool"
class = "RecommendedFees"
inputs = ["recommended_fees", "mempool_blocks_fee"]
serializer = "fee_analysis_serializer"
Running the Example
pip install pymempool
apiout run --config mempool_apis.toml --serializers mempool_serializers.toml --json
How It Works
Both APIs are fetched first:
recommended_feesandmempool_blocks_feeThe post-processor references
client = "mempool"to use thepymempoolmoduleThe
RecommendedFeesclass is instantiated with both resultsThe output is serialized using
fee_analysis_serializerThe result appears in the output under the name
fee_analysis
Configuration Format
[[post_processors]]
name = "processor_name" # Required: unique identifier
module = "module_name" # Required if not using client reference
client = "client_name" # Optional: reference to client for module
class = "ClassName" # Required: class to instantiate
method = "method_name" # Optional: method to call
inputs = ["api1", "api2"] # Required: list of API names
serializer = "serializer_name" # Optional: serializer reference
Key Features
Use client references to avoid repeating module names
Use any existing Python class from installed packages
Combine data from multiple API calls
Chain multiple post-processors together
Optional serialization of output
Later post-processors can reference earlier ones
Example Use Cases
Combining fee data from multiple endpoints (as shown above)
Calculating statistics across multiple API responses
Aggregating data from different sources
Transforming API responses into domain objects
Variable Substitution Example
Dynamic URL and Parameter Building
Use ${param_name} syntax for dynamic configuration with variable substitution:
Configuration with Variable Substitution
context7_docs.toml:
[[apis]]
name = "get_docs"
module = "requests"
client_class = "Session"
method = "get"
url = "https://context7.com/api/v1/${library_id}?type=json&topic=${topic}&tokens=${tokens}"
method_params = {library_id = "", topic = "default", tokens = 1000}
Running with Different Parameters
# Get Next.js hooks documentation
apiout run -c context7_docs.toml -p library_id=/vercel/next.js -p topic=hooks -p tokens=3000 --json
# Get React documentation
apiout run -c context7_docs.toml -p library_id=/facebook/react -p topic=components -p tokens=5000 --json
Environment Variable Integration
# Set environment variables
export CONTEXT7_TOKENS=2000
export DEFAULT_LIBRARY="/vercel/next.js"
# Use environment variables as fallbacks
apiout run -c context7_docs.toml -p topic=hooks --json
Advanced Substitution Examples
Multiple Variable Sources
[clients.weather_client]
module = "openmeteo_requests"
client_class = "Client"
init_params = {base_url = "https://api.open-meteo.com"}
[[apis]]
name = "city_weather"
client = "weather_client"
method = "weather_api"
url = "${base_url}/v1/forecast"
method_params = {latitude = 52.52, longitude = 13.41, units = "metric"}
[apis.params]
latitude = "${latitude}"
longitude = "${longitude}"
current = ["temperature_2m", "relative_humidity_2m"]
units = "${units}"
[apis.headers]
User-Agent = "apiout-client/${units}"
Runtime Override
# Override coordinates and units
echo '{"latitude": 48.8566, "longitude": 2.3522, "units": "imperial"}' | apiout run -c weather.toml --json
Benefits of Variable Substitution
Dynamic Configuration: Change URLs and parameters without editing config files
Environment Integration: Use environment variables for secrets and defaults
Template Reuse: Same config works for different APIs by changing parameters
CI/CD Friendly: Easy to integrate into automated workflows
Security: Keep sensitive values in environment variables, not config files
Variable Resolution Priority
Runtime parameters (
-pflags or JSON stdin) - highest prioritymethod_paramsdefaults from configurationEnvironment variables - fallback
This allows flexible configuration management across different environments and use cases.