Pro API¶
The Pro API only returns and accepts JSON data. API responses are returned as data models that can be interacted with using dot notation.
Pagination¶
Some Pro API read operations support pagination. The API will return a partial response if there are more results than the set page size of the request. To obtain more results the next page must be requested.
The SDK uses a Paginator
to automatically handle this. If the total number of results in the first request are greater than the page size the paginator will fetch all of the remaining pages concurrently.
Tip
If you have large number of records in a paginated request, you may find that using a smaller page size is faster than setting a larger (or max) page size.
Paginators can either return the full response of all pages at once, or it can return an iterator to yield the page objects.
The curated methods will return all results by default. Each operation that supports pagination allows this behavior to be overridden to return the generator.
>>> from jamf_pro_sdk import JamfProClient, BasicAuthProvider
>>> client = JamfProClient("dummy.jamfcloud.com", BasicAuthProvider("demo", "tryitout"))
>>> response = client.pro_api.get_computer_inventory_v1()
>>> response
[Computer(id='117', udid='a311b7c8-75ee-48cf-9b1b-a8598f013366', general=ComputerGeneral(name='Backancient',...
>>> for r in response:
... # Interact with return
... pass
...
>>>
>>> response = client.pro_api.get_computer_inventory_v1(return_generator=True)
>>> response
<generator object Paginator._request at 0x105290120>
>>> for page in response:
... # Interact with the page
... for r in page.results:
... # Interact with return
... pass
...
>>>
The paginator object itself will return the generator by default. This can be overridden in much the same way.
>>> from jamf_pro_sdk import JamfProClient, BasicAuthProvider
>>> from jamf_pro_sdk.clients.pro_api.pagination import Paginator
>>> from jamf_pro_sdk.models.pro.computers import Computer
>>> client = JamfProClient("dummy.jamfcloud.com", BasicAuthProvider("demo", "tryitout"))
>>> paginator = Paginator(api_client=client.pro_api, resource_path="v1/computers-inventory", return_model=Computer)
>>> paginator()
<generator object Paginator._request at 0x1052c2dd0>
>>> paginator(return_generator=False)
[Computer(id='117', udid='a311b7c8-75ee-48cf-9b1b-a8598f013366', general=ComputerGeneral(name='Backancient',...
Many paginated API read operations also support query parameters to filter and sort the results so you can reduce the number of items returned in a request.
The SDK provides programmatic interfaces for both of these options that will properly construct the expressions.
Filtering¶
A filter expression is returned from a FilterField
object when one of the operators is called.
The example below creates a filter expression requiring the ID of every result must be equal to 1
.
>>> from jamf_pro_sdk.clients.pro_api.pagination import FilterField
>>> filter_expression = FilterField("id").eq(1)
>>> print(filter_expression)
id==1
>>>
Filters can be combined together using Python’s &
and |
binary operands.
The example below creates a filter expression requiring the ID of every result is below 100
and the value of the asset tag is below 1000
.
>>> from jamf_pro_sdk.clients.pro_api.pagination import FilterField
>>> filter_expression = FilterField("id").gt(100) & FilterField("general.assetTag").lt(1000)
>>> print(filter_expression)
id>100;general.assetTag<1000
>>>
AND
operators take precedence and are evaluated before any OR
operators. Filters can be grouped together and the result of the inner filters will be evaluated in order with the outer filters.
The example below creates a filter expression requiring either the barcode or the asset tag of every result to be below 1000
and the ID be below 100
.
>>> from jamf_pro_sdk.clients.pro_api.pagination import FilterField, filter_group
>>> filter_expression = filter_group(FilterField("general.barcode1").lt(1000) | FilterField("general.assetTag").lt(1000)) & FilterField("id").gte(100)
>>> print(filter_expression)
(general.barcode1<1000,general.assetTag<1000);id>=100
>>>
Sorting¶
Sorting expressions work similarly. A sort expression is returned from a SortField
object when one of the operators is called.
>>> from jamf_pro_sdk.clients.pro_api.pagination import SortField
>>> sort_expression = SortField("id").asc()
>>> print(sort_expression)
id:asc
>>>
Sortable fields can be combined together using Python’s &
binary operands. Unlike filter, sort fields are evaluated from left-to-right. The leftmost field will be the first sort, and then the next, and so on.
>>> from jamf_pro_sdk.clients.pro_api.pagination import SortField
>>> sort_expression = SortField("name").asc() & SortField("id").desc()
>>> print(sort_expression)
name:asc,id:desc
>>>
Full Example¶
Here is an example of a paginated request using the SDK with the sorting and filtering options.
>>> from jamf_pro_sdk import JamfProClient, BasicAuthProvider
>>> from jamf_pro_sdk.clients.pro_api.pagination import FilterField, SortField
>>> client = JamfProClient(
... server="dummy.jamfcloud.com",
... credentials=BasicAuthProvider("demo", "tryitout")
... )
>>>
>>> response = client.pro_api.get_computer_inventory_v1(
... sections=["GENERAL", "USER_AND_LOCATION", "OPERATING_SYSTEM"],
... page_size=1000,
... sort_expression=SortField("id").asc(),
... filter_expression=FilterField("operatingSystem.version").lt("13.")
... )
>>>
MDM Commands¶
The SDK provides MDM commands in the form of models that are passed to the send_mdm_command_preview()
method.
>>> from jamf_pro_sdk import JamfProClient, BasicAuthProvider
>>> from jamf_pro_sdk.models.pro.mdm import LogOutUserCommand
>>> client = JamfProClient("dummy.jamfcloud.com", BasicAuthProvider("demo", "tryitout"))
>>> response client.pro_api.send_mdm_command_preview(
... management_ids=["4eecc1fb-f52d-48c5-9560-c246b23601d3"],
... command=LogOutUserCommand()
... )
The response
will contain an array of SendMdmCommandResponse
objects that have the IDs of the commands sent. Those IDs can be used with the uuid
filter of get_mdm_commands_v2()
to get the command’s status.
Basic MDM commands with no additional properties can be passed as instantiated objects as shown above with the LogOutUserCommand
command. For other commands the additional properties can be set after instantiation, or a dictionary of values can be unpacked.
>>> from jamf_pro_sdk.models.pro.mdm import EraseDeviceCommand
>>> command = EraseDeviceCommand()
>>> command.pin = "123456"
>>> command = EraseDeviceCommand(**{"pin": "123456"})
Commands with required properties must have those values passed at instantiation.
>>> from jamf_pro_sdk.models.pro.mdm import EnableLostModeCommand
>>> command = EnableLostModeCommand()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 3 validation errors for EnableLostModeCommand
lostModeMessage
field required (type=value_error.missing)
lostModePhone
field required (type=value_error.missing)
lostModeFootnote
field required (type=value_error.missing)
>>> command = EnableLostModeCommand(
... lostModeMessage="Please return me to my owner.",
... lostModePhone="123-456-7890",
... lostModeFootnote="No reward."
... )
>>>
Read the documentation for MDM Commands for all support MDM commands and their properties.