Appearance
Custom Actions
Some SDK controllers expose methods beyond standard CRUD. This page documents the three custom action patterns you will encounter.
Variant create
Some controllers (DnsRecord, Address) require exactly one discriminating relationship to be set before calling store(). These controllers expose explicit store_with_* helpers, which are the recommended style.
Using explicit helpers (recommended)
python
import asyncio
from cacholong_sdk import connection, DnsRecord, ResourceTuple
async def main():
async with connection("https://api.cacholong.eu/api/v1/", "YOUR-API-KEY") as api:
ctrl = DnsRecord(api)
record = ctrl.create()
record["dns-zone"] = ResourceTuple("ZONE-UUID", "dns-zones")
record["name"] = "www.example.com"
record["dns-record-type"] = "A"
record["content"] = "192.0.2.1"
record["ttl"] = 300
await ctrl.store_with_dns_zone(record)
asyncio.run(main())Using auto-detecting store()
store() auto-detects which discriminating relationship is set and calls the correct variant internally. The result is identical to the explicit helper:
python
import asyncio
from cacholong_sdk import connection, DnsRecord, ResourceTuple
async def main():
async with connection("https://api.cacholong.eu/api/v1/", "YOUR-API-KEY") as api:
ctrl = DnsRecord(api)
record = ctrl.create()
record["dns-zone"] = ResourceTuple("ZONE-UUID", "dns-zones")
record["name"] = "www.example.com"
record["dns-record-type"] = "A"
record["content"] = "192.0.2.1"
record["ttl"] = 300
await ctrl.store(record) # auto-detects the dns-zone relationship
asyncio.run(main())Validation errors
store() raises ValidationException if no discriminating relationship is set, or if more than one is set:
python
from cacholong_sdk import ValidationException
try:
await ctrl.store(record) # no dns-zone or dns-template set
except ValidationException as e:
print(e.message)
# "One of the following relationships is required: dns_zone, dns_template"
try:
await ctrl.store(record) # both dns-zone and dns-template set
except ValidationException as e:
print(e.message)
# "Only one of the following relationships may be set: dns_zone, dns_template"Available helpers per variant controller:
| Controller | Helpers |
|---|---|
DnsRecord | store_with_dns_zone, store_with_dns_template |
Address | store_with_user, store_with_company |
ID-based lifecycle actions
Some controllers expose action methods that accept only a UUID. The controller fetches the resource internally before performing the action — the caller only needs the ID.
DnsZoneRestorePoint.rollback(resource_id) is an example:
python
import asyncio
from cacholong_sdk import connection, DnsZoneRestorePoint
async def main():
async with connection("https://api.cacholong.eu/api/v1/", "YOUR-API-KEY") as api:
ctrl = DnsZoneRestorePoint(api)
await ctrl.rollback("RESTORE-POINT-UUID")
asyncio.run(main())Model-based lifecycle actions
Some actions require the caller to build or fetch a model, optionally set fields, and then call the action method. The method POSTs to a custom URL via model.commit(custom_url). This is the underlying mechanism behind variant create as well.
The example below illustrates the pattern using DnsZone.import_(), which is available in the cacholong-cli internal package. The public SDK (cacholong-cloud-cli) does not currently expose model-based lifecycle actions, but the pattern is shown here so you can recognise it if you encounter it:
python
import asyncio
from cacholong_sdk import connection, DnsZone
async def main():
async with connection("https://api.cacholong.eu/api/v1/", "YOUR-API-KEY") as api:
ctrl = DnsZone(api)
# Build a model representing the action payload
zone = ctrl.create()
zone["domain"] = "example.com"
zone["zone_data"] = "$ORIGIN example.com.\n..."
# The action method POSTs to a custom URL via model.commit(custom_url)
await ctrl.import_(zone)
asyncio.run(main())When you encounter a controller method that is not store, update, or destroy, it is likely a model-based lifecycle action following this pattern.