Core Concepts

The linode_api4 package, and the API V4, have a few ideas that will help you more quickly become proficient with their usage. This page assumes you’ve read the Getting Started guide, and know the basics of authentication already.

Filtering

Collections of objects in the API can be filtered to make their results more useful. For example, instead of having to do this filtering yourself on the full list, you can ask the API for all Linode Instances you own belonging to a certain group. This library implements filtering with a SQLAlchemy-like syntax, where a model’s attributes may be used in comparisons to generate filters. For example:

prod_linodes = client.linode.instances(Instance.group == "production")

Filters may be combined using boolean operators similar to SQLAlchemy:

# and_ and or_ can be imported from the linode package to combine filters
from linode_api4 import or_
prod_or_staging = client.linode.instances(or_(Instance.group == "production",
                                                  Instance.group == "staging"))

# and_ isn't strictly necessary, as it's the default when passing multiple
# filters to a collection
prod_and_green = client.linode.instances(Instance.group == "production",
                                             Instance.label.contains("green"))

Filters are generally only applicable for the type of model you are querying, but can be combined to your heart’s content. For numeric fields, the standard numeric comparisons are accepted, and work as you’d expect. See Filtering Collections for full details.

Models

This library represents objects the API returns as “models.” Most methods of LinodeClient return models or lists of models, and all models behave in a similar manner.

Creating Models

In addition to looking up models from collections, you can simply import the model class and create it by ID.:

from linode_api4 import Instance
my_linode = Instance(client, 123)

All models take a LinodeClient as their first parameter, and their ID as the second. For derived models (models that belong to another model), the parent model’s ID is taken as a third argument to the constructor (i.e. to construct a Disk you pass a LinodeClient, the disk’s ID, then the parent Linode Instance’s ID).

Be aware that when creating a model this way, it is _not_ loaded from the API immediately. Models in this library are lazy-loaded, and will not be looked up until one of their attributes that is currently unknown is accessed.

Lazy Loading

If a model is created, but not yet retrieved from the API, its attributes will be unpopulated. As soon as an unpopulated attribute is accessed, an API call is emitted to retrieve that value (and the rest of the attributes in the model) from the API. For example:

my_linode.id # no API call emitted - this was set on creation
my_linode.label # API call emitted - entire object is loaded from response
my_linode.group # no API call emitted - this was loaded above

Note

When loading a model in this fashion, if the model does not exist in the API or you do not have access to it, an ApiError is raised. If you want to load a model in a more predictable manner, see LinodeClient.load

Volatile Attributes

Some attributes of models are marked volatile. A volatile attribute will become stale after a short time, and if accessed when its value is stale, will refresh itself (and the entire object) from the API to ensure the value is current.:

my_linode.boot()
my_linode.status # booting
time.sleep(20) # wait for my_linode.status to become stale
my_linode.status # running

Note

While it is often safe to loop on a volatile attribute, be aware that there is no guarantee that their value will ever change - be sure that any such loops have another exit condition to prevent your application from hanging if something you didn’t expect happens.

Updating and Deleting Models

Most models have some number of mutable attributes. Updating a model is as simple as assigning a new value to these attributes and then saving the model. Many models can also be deleted in a similar fashion.:

my_linode.label = "new-label"
my_linode.group = "new-group"
my_linode.save() # emits an API call to update label and group

my_linode.delete() # emits an API call to delete my_linode

Note

Saving a model may fail if the values you are attempting to save are invalid. If the values you are attemting to save are coming from an untrusted source, be sure to handle a potential ApiError raised by the API returning an unsuccessful response code.

Relationships

Many models are related to other models (for example a Linode Instance has disks, configs, volumes, backups, a region, etc). Related attributes are accessed like any other attribute on the model, and will emit an API call to retrieve the related models if necessary.:

len(my_linode.disks) # emits an API call to retrieve related disks
my_linode.disks[0] # no API call emitted - this is already loaded

my_linode.region.id # no API call emitted - IDs are already populated
my_linode.region.country # API call emitted - retrieves region object