# FastCF


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

`fastcflare` provides an async Cloudflare API client built from
Cloudflare’s OpenAPI schema. Use
[`CloudflareApi`](https://AnswerDotAI.github.io/fastcflare/core.html#cloudflareapi)
to browse API operations, manage zones and DNS records, and create
scoped tokens. The examples below show user-token access and
account-owned tokens.

``` python
from fastcore.utils import *
from fastcflare import *
```

## Quickstart

``` python
from fastcflare import *
```

``` python
usrtok = os.environ['CLOUDFLARE_USR_TOK']
```

``` python
ucf = CloudflareApi(token=usrtok)
(await ucf.verify()).result.status
```

    'active'

``` python
(await ucf.zones.list()).result[0].name
```

    'aaa.as'

### Create a token

Create a token with Zone Read and DNS Write permissions for one domain.
Replace `xxx` with the domain name. The client used to create it must
have permission to create tokens:

``` py
doms = ['xxx']
pnms = ('Zone Read', 'DNS Write')
tok = await ucf.create_token(doms, pnms, 'domain mgt')
dns_token = tok.result.value
```

Store the token securely. For APIs that accept a Global API Key,
construct the client with
`CloudflareApi(email=os.environ['CLOUDFLARE_EML_ADD'], api_key=os.environ['CLOUDFLARE_API_KEY'])`
instead.

Use the new token to list DNS records, create a test A record, and
delete that record. This changes DNS records in an existing zone; it
does not create or delete the domain:

``` python
domnm = 'xxx'
zones = (await ucf.zones.list(name=domnm)).result
zid_sp = zones[0].id

dcf = CloudflareApi(token=dns_token)
print((await dcf.zones.dns_records.list(zone_id=zid_sp)).result[:3])
rec = await dcf.zones.dns_records.post(zid_sp, type='A', name='test-delete-me.xxx', content='192.0.2.1', ttl=1)
print(rec.result.id, rec.result.name)
print((await dcf.zones.dns_records.delete(zid_sp, rec.result.id)).result.id)
```

## Intro to Account Tokens

[Account-owned API
tokens](https://developers.cloudflare.com/fundamentals/api/get-started/account-owned-tokens/)
belong to an account and act as service principals with their own
permissions. They support CI/CD and service integrations that need to
keep working after the creating user leaves the organization. The API
endpoint is `/accounts/{id}/tokens`.

### Creating Account Tokens

Cloudflare requires Super Administrator permission to create or update
account-owned tokens. The [creation
endpoint](https://developers.cloudflare.com/api/python/resources/accounts/subresources/tokens/methods/create/)
accepts an API token with `Account API Tokens Write`. The following
example uses the official Cloudflare Python SDK with token
authentication:

``` python
from cloudflare import Cloudflare
cf = Cloudflare(api_token=your_cf_token)
accts = cf.accounts.list()
acct_id = next(iter(accts)).id
```

Look up permission groups available to the account:

``` python
groups = list(cf.accounts.tokens.permission_groups.list(account_id=acct_id))
{g.name: g.id for g in groups if 'dns' in g.name.lower() or 'zone' in g.name.lower()}
```

For account-owned tokens, nest zone resources under the account
resource. This example grants Zone Read and DNS Write across its zones:

``` python
tok = cf.accounts.tokens.create(account_id=acct_id, name="dns-all-zones", policies=[{
    "effect": "allow",
    "resources": {f"com.cloudflare.api.account.{acct_id}": {"com.cloudflare.api.account.zone.*": "*"}},
    "permission_groups": [{"id": g.id} for g in groups if g.name in ('Zone Read', 'DNS Write')]
}])
dns_tok = tok.value  # Store securely; the value is only returned at creation
```

A zone resource without the enclosing account, such as
`{"com.cloudflare.api.account.zone.*": "*"}`, fails with: “Must specify
a zone for account owned tokens, or nest zone under specific account
resource”. Keep the nested format even when granting access to all
zones.

## Development

The op surface comes from `cf_spec.py`, Cloudflare’s OpenAPI schema in
fastspec’s compact form. Refresh it from Cloudflare’s published schema
with `tools/build.py`, then review the diff: op names can shift when the
schema changes.
