Skip to main content

A package for interacting with version 2 of the Onspring API.

Project description

Onspring API Python SDK

The python SDK for version 2 of the Onspring API is meant to simplify development in Python for Onspring customers who want to build integrations with their Onspring instance.

Note: This is an unofficial SDK for the Onspring API. It was not built in consultation with Onspring Technologies LLC or a member of their development team.

This SDK was developed independently using their existing C# SDK, their swagger page, and api documentation as the starting point with the intention of making development of integrations done in Python with an Onspring instance quicker and more convenient.

Dependencies

Python

Requires use of Python 3.10.0 or later.

httpx

All methods for OnspringClient and AsyncOnspringClient make use of the httpx library to interact with the endpoints of version 2 of the Onspring API.

Installation

Install the SDK using pip:

pip install OnspringApiSdk

API Key

In order to successfully interact with the Onspring Api you will need an API key. API keys are obtained by an Onspring user with permissions to at least Read API Keys for your instance via the following steps:

  1. Login to the Onspring instance.
  2. Navigate to Administration > Security > API Keys
  3. On the list page, add a new API Key - this will require Create permissions - or click an existing API key to view its details.
  4. Click on the Developer Information tab.
  5. Copy the X-ApiKey Header value from this tab.

Start Coding

OnspringClient

The most common way to use the SDK is to create an OnspringClient instance and call its methods. Its constructor requires two parameters:

  • url - currently this should always be: https://api.onspring.com
  • key - the value obtained by following the steps in the API Key section

It is best practice to read these values in from a configuration file for both flexibility and security purposes.

Example config.ini file:

[prod]
key = 000000ffffff000000ffffff/00000000-ffff-0000-ffff-000000000000
url = https://api.onspring.com

Example constructing OnspringClient:

from onspring_api_sdk import OnspringClient
from configparser import ConfigParser

cfg = ConfigParser()
cfg.read('config.ini')

key = cfg['prod']['key']
url = cfg['prod']['url']

client = OnspringClient(url, key)

AsyncOnspringClient

An async client is also available for use with asyncio:

from onspring_api_sdk import AsyncOnspringClient

async with AsyncOnspringClient(url, key) as client:
    response = await client.get_apps()

All methods mirror the sync client with await prefixed.

ApiResponse

Each client method returns an ApiResponse object with the following properties:

  • status_code - The http status code of the response.
  • is_successful - Whether the request was successful (status < 400).
  • data - If the request was successful will contain the response data deserialized to Pydantic models.
  • message - A message that may provide more detail about the requests success or failure.
  • raw_response - Exposes the raw httpx.Response object if you'd like to handle it directly.

The goal with this ApiResponse object is to provide the flexibility to do with the response what you'd like while already having the JSON response deserialized to Python objects.

Error Handling

You can check is_successful or call raise_for_status() to raise an exception on failure:

from onspring_api_sdk import OnspringError, OnspringAuthenticationError

response = client.get_apps()

if not response.is_successful:
    print(f'Request failed: {response.message}')

# Or raise on failure:
try:
    response.raise_for_status()
except OnspringAuthenticationError:
    print('Check your API key')
except OnspringError as e:
    print(f'Request failed: {e}')

Full API Documentation

You may wish to refer to the full Onspring API documentation when determining which values to pass as parameters to some of the client methods. There is also a swagger page that you can use for making exploratory requests.

Example Code

The examples that follow assume you have created an OnspringClient as described in the Start Coding section.

Connectivity

Verify connectivity

if client.can_connect():
    print('Connected successfully')
else:
    print('Attempt to connect failed')

Apps

Get Apps

Returns a paged collection of apps and/or surveys that can be paged through. By default the page size is 50 and page number is 1.

response = client.get_apps()

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for app in response.data.apps:
    print(f'Id: {app.id}')
    print(f'Name: {app.name}')
    print(f'href: {app.href}')

You can set your own page size and page number (max is 1,000) as well.

from onspring_api_sdk.models import PagingRequest

paging_request = PagingRequest(page_number=1, page_size=100)
response = client.get_apps(paging_request=paging_request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for app in response.data.apps:
    print(f'Id: {app.id}')
    print(f'Name: {app.name}')
    print(f'href: {app.href}')

Get App By Id

Returns an Onspring app or survey according to provided id.

response = client.get_app_by_id(app_id=195)

print(f'Status Code: {response.status_code}')
print(f'id: {response.data.app.id}')
print(f'Name: {response.data.app.name}')
print(f'href: {response.data.app.href}')

Get Apps By Ids

Returns a collection of Onspring apps and/or surveys according to provided ids.

response = client.get_apps_by_ids(app_ids=[195, 240])

print(f'Status Code: {response.status_code}')
print(f'Count: {response.data.count}')

for app in response.data.apps:
    print(f'Id: {app.id}')
    print(f'Name: {app.name}')
    print(f'href: {app.href}')

Fields

Print Field Helper

An example helper for printing field details used in the following examples:

from onspring_api_sdk.models import OnspringField


def print_field(field: OnspringField):

    print('Field:')
    print(f' Id: {field.id}')
    print(f' App Id: {field.app_id}')
    print(f' Name: {field.name}')
    print(f' Type: {field.type}')
    print(f' Status: {field.status}')
    print(f' Is Required: {field.is_required}')
    print(f' Is Unique: {field.is_unique}')

    if field.type == 'Formula':
        print(f' Output Type: {field.output_type}')

    if field.type == 'List':
        print(f' Multiplicity: {field.multiplicity}')

        if field.values:
            print(' Values:')

            for value in field.values:
                print(f'  {value}')

Get Field By Id

Returns an Onspring field according to provided id.

response = client.get_field_by_id(field_id=9686)

print(f'Status Code: {response.status_code}')
print_field(response.data.field)

Get Fields By Ids

Returns a collection of Onspring fields according to provided ids.

response = client.get_fields_by_ids(field_ids=[9686, 9687])

print(f'Status Code: {response.status_code}')
print(f'Count: {response.data.count}')

for field in response.data.fields:
    print_field(field)

Get Fields By App Id

Returns a paged collection of fields that can be paged through. By default the page size is 50 and page number is 1.

response = client.get_fields_by_app_id(app_id=195)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for field in response.data.fields:
    print_field(field)

You can set your own page size and page number (max is 1,000) as well.

from onspring_api_sdk.models import PagingRequest

paging_request = PagingRequest(page_number=1, page_size=100)
response = client.get_fields_by_app_id(app_id=195, paging_request=paging_request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for field in response.data.fields:
    print_field(field)

Files

Get File Info By Id

Returns the Onspring file's metadata.

response = client.get_file_info_by_id(record_id=1, field_id=6990, file_id=274)

print(f'Status Code: {response.status_code}')
print(f'Name: {response.data.file_info.name}')
print(f'Type: {response.data.file_info.type}')
print(f'Owner: {response.data.file_info.owner}')
print(f'Content Type: {response.data.file_info.content_type}')
print(f'Created Date: {response.data.file_info.created_date}')
print(f'Modified Date: {response.data.file_info.modified_date}')
print(f'File Href: {response.data.file_info.file_href}')

Get File By Id

Returns the file itself.

response = client.get_file_by_id(record_id=1, field_id=6990, file_id=274)

print(f'Status Code: {response.status_code}')
print(f'Name: {response.data.file.name}')
print(f'Content Type: {response.data.file.content_type}')
print(f'Content Length: {response.data.file.content_length}')

file_path = f'C:\\Users\\sfree\\Documents\\Temp\\{response.data.file.name}'

with open(file_path, "wb") as f:
    f.write(response.data.file.content)

print(f'File Location: {file_path}')

Save File

from onspring_api_sdk.models import SaveFileRequest
from datetime import datetime
import os
import mimetypes

file_path = 'C:\\Users\\sfree\\Documents\\Temp\\Test Attachment.txt'
file_name = os.path.basename(file_path)
content_type = mimetypes.guess_type(file_path)[0]

request = SaveFileRequest(
    record_id=60,
    field_id=6989,
    file_name=file_name,
    file_path=file_path,
    content_type=content_type,
    notes='Initial revision',
    modified_date=datetime.now(),
)

response = client.save_file(request)

print(f'Status Code: {response.status_code}')
print(f'File Id: {response.data.id}')

Delete File By Id

response = client.delete_file_by_id(record_id=60, field_id=6989, file_id=231)

print(f'Status Code: {response.status_code}')
print(f'Message: {response.message}')

Lists

Add Or Update List Value

To add a list value don't provide an id value.

from onspring_api_sdk.models import ListItemRequest

request = ListItemRequest(
    list_id=906,
    name='Not Started',
    numeric_value=0,
    color='#ffffff',
)

response = client.add_or_update_list_item(request)

print(f'Status Code: {response.status_code}')
print(f'Id: {response.data.id}')

To update a list value provide an id value.

from onspring_api_sdk.models import ListItemRequest
import uuid

request = ListItemRequest(
    list_id=906,
    name='Pending',
    id=uuid.UUID('4118d53a-9121-4345-8682-07f23d606daa'),
    numeric_value=0,
    color='#ffffff',
)

response = client.add_or_update_list_item(request)

print(f'Status Code: {response.status_code}')
print(f'Id: {response.data.id}')

Delete List Value

response = client.delete_list_item(
    list_id=906,
    item_id='36f94d8c-2b9d-465e-9ad1-ede04109efc9',
)

print(f'Status Code: {response.status_code}')
print(f'Message: {response.message}')

Records

Get Records By App Id

Returns a paged collection of records that can be paged through. By default the page size is 50 and page number is 1.

from onspring_api_sdk.models import GetRecordsByAppRequest

request = GetRecordsByAppRequest(app_id=195)
response = client.get_records_by_app_id(request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

You can set your own page size and page number (max is 1,000) as well. In addition to specifying what field values to return and in what format (Raw vs. Formatted) to return them.

from onspring_api_sdk.models import GetRecordsByAppRequest
from onspring_api_sdk.enums import DataFormat

request = GetRecordsByAppRequest(
    app_id=195,
    field_ids=[9686],
    data_format=DataFormat.Formatted.name,
    page_number=1,
    page_size=10,
)

response = client.get_records_by_app_id(request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

Get Record By Id

Returns an Onspring record based on the provided app and record ids.

from onspring_api_sdk.models import GetRecordByIdRequest

request = GetRecordByIdRequest(app_id=195, record_id=60)
response = client.get_record_by_id(request)

print(f'Status Code: {response.status_code}')
print(f'AppId: {response.data.app_id}')
print(f'RecordId: {response.data.record_id}')

for field in response.data.fields:
    print(f'Type: {field.type}')
    print(f'FieldId: {field.field_id}')
    print(f'Value: {field.value}')

You can also specify what field values to return and in what format (Raw vs. Formatted) to return them.

from onspring_api_sdk.models import GetRecordByIdRequest
from onspring_api_sdk.enums import DataFormat

request = GetRecordByIdRequest(
    app_id=195,
    record_id=60,
    field_ids=[9686],
    data_format=DataFormat.Formatted.name,
)

response = client.get_record_by_id(request)

print(f'Status Code: {response.status_code}')
print(f'AppId: {response.data.app_id}')
print(f'RecordId: {response.data.record_id}')

for field in response.data.fields:
    print(f'Type: {field.type}')
    print(f'FieldId: {field.field_id}')
    print(f'Value: {field.value}')

Delete Record By Id

response = client.delete_record_by_id(app_id=195, record_id=60)

print(f'Status Code: {response.status_code}')
print(f'Message: {response.message}')

Get Records By Ids

Returns a collection of Onspring records based on the provided appId and recordIds.

from onspring_api_sdk.models import GetBatchRecordsRequest

request = GetBatchRecordsRequest(app_id=195, record_ids=[1, 2, 3])
response = client.get_records_by_ids(request)

print(f'Status Code: {response.status_code}')
print(f'Count: {response.data.count}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

You can also specify what field values to return and in what format (Raw vs. Formatted) to return them.

from onspring_api_sdk.models import GetBatchRecordsRequest
from onspring_api_sdk.enums import DataFormat

request = GetBatchRecordsRequest(
    app_id=195,
    record_ids=[1, 2, 3],
    field_ids=[9686],
    data_format=DataFormat.Formatted.name,
)

response = client.get_records_by_ids(request)

print(f'Status Code: {response.status_code}')
print(f'Count: {response.data.count}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

Query Records

Returns a paged collection of records based on a criteria that can be paged through. By default the page size is 50 and page number is 1.

from onspring_api_sdk.models import QueryRecordsRequest

field_id = 6983
operator = 'eq'
value = "'Test Task 5'"

request = QueryRecordsRequest(app_id=195, filter=f'{field_id} {operator} {value}')
response = client.query_records(request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

You can set your own page size and page number (max is 1,000) as well. In addition to specifying what field values to return and in what format (Raw vs. Formatted) to return them.

from onspring_api_sdk.models import QueryRecordsRequest
from onspring_api_sdk.enums import DataFormat

field_id = 6983
operator = 'eq'
value = "'Test Task 5'"

request = QueryRecordsRequest(
    app_id=195,
    filter=f'{field_id} {operator} {value}',
    field_ids=[9686],
    data_format=DataFormat.Formatted.name,
    page_number=1,
    page_size=10,
)

response = client.query_records(request)

print(f'Status Code: {response.status_code}')
print(f'Page Size: {response.data.page_size}')
print(f'Page Number: {response.data.page_number}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')

for record in response.data.records:
    print(f'AppId: {record.app_id}')
    print(f'RecordId: {record.record_id}')

    for field in record.fields:
        print(f'Type: {field.type}')
        print(f'FieldId: {field.field_id}')
        print(f'Value: {field.value}')

For further details on constructing the filter parameter please refer to the documentation for v2 of the Onspring API.

Add or Update A Record

You can add a record by not providing a record id value. If successful will return the id of the added record.

from onspring_api_sdk.models import (
    StringFieldValue,
    GuidFieldValue,
    DateFieldValue,
    IntegerListValue,
    Record,
)
import uuid
from datetime import datetime

fields = []

status = uuid.UUID('4118d53a-9121-4345-8682-07f23d606daa')
due_date = datetime.utcnow()

fields.append(StringFieldValue(field_id=6983, value='Test Task via API'))
fields.append(StringFieldValue(field_id=6984, value='This is a task.'))
fields.append(GuidFieldValue(field_id=6986, value=status))
fields.append(DateFieldValue(field_id=6985, value=due_date))
fields.append(IntegerListValue(field_id=6987, value=[4]))

record = Record(app_id=195, fields=fields)

response = client.add_or_update_record(record)

print(f'Status Code: {response.status_code}')
print(f'Id: {response.data.id}')

for warning in response.data.warnings:
    print(f'Warning: {warning}')

You can update a record by providing its id. If successful will return the id of record updated.

from onspring_api_sdk.models import (
    StringFieldValue,
    GuidFieldValue,
    DateFieldValue,
    IntegerListValue,
    Record,
)
import uuid
from datetime import datetime

fields = []

status = uuid.UUID('1c1c5f7e-cd03-4b70-9790-0f83b24b5863')
due_date = datetime.utcnow()

fields.append(StringFieldValue(field_id=6983, value='Test Task via API'))
fields.append(StringFieldValue(field_id=6984, value='This is a task.'))
fields.append(GuidFieldValue(field_id=6986, value=status))
fields.append(DateFieldValue(field_id=6985, value=due_date))
fields.append(IntegerListValue(field_id=6987, value=[4]))

record = Record(app_id=195, fields=fields, record_id=103)

response = client.add_or_update_record(record)

print(f'Status Code: {response.status_code}')
print(f'Id: {response.data.id}')

for warning in response.data.warnings:
    print(f'Warning: {warning}')

Delete Records By Ids

from onspring_api_sdk.models import DeleteBatchRecordsRequest

request = DeleteBatchRecordsRequest(app_id=195, record_ids=[1, 2, 3])

response = client.delete_records_by_ids(request)

print(f'Status Code: {response.status_code}')
print(f'Message: {response.message}')

Reports

Get Report By Id

Returns the report for the provided id.

from onspring_api_sdk.models import GetReportByIdRequest

request = GetReportByIdRequest(report_id=53)
response = client.get_report_by_id(request)

print(f'Status Code: {response.status_code}')
print('Columns:')
print(f'{", ".join(response.data.columns)}')
print('Rows:')

for row in response.data.rows:
    cells = ', '.join([str(cell) for cell in row.cells])
    print(f'Record Id {row.record_id}: {cells}')

You can also specify the format of the data in the report as well as whether you are requesting the report's data or its chart data.

from onspring_api_sdk.models import GetReportByIdRequest
from onspring_api_sdk.enums import DataFormat, ReportDataType

request = GetReportByIdRequest(
    report_id=53,
    api_data_format=DataFormat.Formatted.name,
    data_type=ReportDataType.ChartData.name,
)

response = client.get_report_by_id(request)

print(f'Status Code: {response.status_code}')
print('Columns:')
print(f'{", ".join(response.data.columns)}')
print('Rows:')

for row in response.data.rows:
    cells = ', '.join([str(cell) for cell in row.cells])
    print(f'Record Id {row.record_id}: {cells}')

Get Reports By App Id

Returns a paged collection of reports that can be paged through. By default the page size is 50 and page number is 1.

response = client.get_reports_by_app_id(app_id=195)

print(f'Status Code: {response.status_code}')
print('Reports:')

for report in response.data.reports:
    print(f' Id: {report.id}')
    print(f' Name: {report.name}')
    print(f' Description: {report.description}')

You can set your own page size and page number (max is 1,000) as well.

from onspring_api_sdk.models import PagingRequest

paging_request = PagingRequest(page_number=1, page_size=10)
response = client.get_reports_by_app_id(app_id=195, paging_request=paging_request)

print(f'Status Code: {response.status_code}')
print(f'Page Number: {response.data.page_number}')
print(f'Page Size: {response.data.page_size}')
print(f'Total Pages: {response.data.total_pages}')
print(f'Total Records: {response.data.total_records}')
print('Reports:')

for report in response.data.reports:
    print(f' Id: {report.id}')
    print(f' Name: {report.name}')
    print(f' Description: {report.description}')

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

onspringapisdk-3.0.0.tar.gz (168.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

onspringapisdk-3.0.0-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

File details

Details for the file onspringapisdk-3.0.0.tar.gz.

File metadata

  • Download URL: onspringapisdk-3.0.0.tar.gz
  • Upload date:
  • Size: 168.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onspringapisdk-3.0.0.tar.gz
Algorithm Hash digest
SHA256 53401b5e333f8b4bd47017c474ec69b65c99c7a689ac69887efa4f50ce0b7069
MD5 f5e8ba00ac89850fca98bd81cce8c407
BLAKE2b-256 9b85decec43591ff09606a405ff2333ed2b93b01d1b61ae38e9be3da7bcb9d81

See more details on using hashes here.

Provenance

The following attestation bundles were made for onspringapisdk-3.0.0.tar.gz:

Publisher: publish.yml on StevanFreeborn/onspring-api-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file onspringapisdk-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: onspringapisdk-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 22.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for onspringapisdk-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2ac6dce02fde536696743e82e6be7898c13611f3b7ae954f9af93d01d17190dc
MD5 0cd457a3ef04a765500f74e41cf21ddc
BLAKE2b-256 1f5d97c4b9c2bce2c658d56f236307b1609461090bc35da906124626e8d039dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for onspringapisdk-3.0.0-py3-none-any.whl:

Publisher: publish.yml on StevanFreeborn/onspring-api-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page