Skip to content

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.

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:

ControllerHelpers
DnsRecordstore_with_dns_zone, store_with_dns_template
Addressstore_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.