From f3c69d3a343c742d420643cdc487fdba299ff100 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 20 Feb 2023 19:12:15 -0600 Subject: [PATCH 01/23] fix: update jsdoc comments for enums --- src/enums/DelegateType.ts | 20 ++++++++++++++++---- src/enums/FileStorageSite.ts | 3 +++ src/enums/FilterOperators.ts | 10 ++++++++++ src/enums/FormulaOutputType.ts | 3 +++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/enums/DelegateType.ts b/src/enums/DelegateType.ts index 5a8c529..57e23fa 100644 --- a/src/enums/DelegateType.ts +++ b/src/enums/DelegateType.ts @@ -1,4 +1,16 @@ -export enum DelegateType { - External = 'External', - Internal = 'Internal', -} +/** + * @enum DelegateType - The type of delegate + */ +export enum DelegateType { + /** + * @constant External - The delegate is external. + * @type {string} + */ + External = 'External', + + /** + * @constant Internal - The delegate is internal. + * @type {string} + */ + Internal = 'Internal', +} diff --git a/src/enums/FileStorageSite.ts b/src/enums/FileStorageSite.ts index 34883a1..bf13da4 100644 --- a/src/enums/FileStorageSite.ts +++ b/src/enums/FileStorageSite.ts @@ -1,3 +1,6 @@ +/** + * @enum FileStorageSite - The site where the file is stored. + */ export enum FileStorageSite { /** * @constant Internal - The file is stored in the internal file storage. diff --git a/src/enums/FilterOperators.ts b/src/enums/FilterOperators.ts index 5210291..b66d368 100644 --- a/src/enums/FilterOperators.ts +++ b/src/enums/FilterOperators.ts @@ -4,60 +4,70 @@ export enum FilterOperators { /** * @constant Equal - The equal operator + * @type {string} * @remarks Can be used with text, auto-number, date, and number fields as well as their formula equivalents. */ Equal = 'eq', /** * @constant NotEqual - The not equal operator + * @type {string} * @remarks Can be used with text, auto-number, date, and number fields as well as their formula equivalents. */ NotEqual = 'ne', /** * @constant Contains - The contains operator + * @type {string} * @remarks Can be used with list fields as well as their formula equivalents. */ Contains = 'contains', /** * @constant IsNull - The is null operator + * @type {string} * @remarks Can be used with text, date, and number fields as well as their formula equivalents. */ IsNull = 'isnull', /** * @constant NotNull - The not null operator + * @type {string} * @remarks Can be used with text, date, and number fields as well as their formula equivalents. */ NotNull = 'notnull', /** * @constant GreaterThan - The greater than operator + * @type {string} * @remarks Can be used with auto-number, date, and number fields as well as their formula equivalents. */ GreaterThan = 'gt', /** * @constant LessThan - The less than operator + * @type {string} * @remarks Can be used with auto-number, date, and number fields as well as their formula equivalents. */ LessThan = 'lt', /** * @constant And - The and operator + * @type {string} * @remarks Can be used to create compound filters. */ And = 'and', /** * @constant Or - The or operator + * @type {string} * @remarks Can be used to create compound filters. */ Or = 'or', /** * @constant Not - The not operator + * @type {string} * @remarks Can be used to negate a filter and create compound filters. */ Not = 'not', diff --git a/src/enums/FormulaOutputType.ts b/src/enums/FormulaOutputType.ts index ca7c9b8..5de8038 100644 --- a/src/enums/FormulaOutputType.ts +++ b/src/enums/FormulaOutputType.ts @@ -1,3 +1,6 @@ +/** + * @enum FormulaOutputType - The type of the formula output. + */ export enum FormulaOutputType { /** * @constant Text - The formula output is a text value. From 396660e80142b82442b3ab08e1f7ab97331499e1 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <=> Date: Mon, 20 Feb 2023 21:08:22 -0600 Subject: [PATCH 02/23] fix: add jsdoc comments to models --- src/models/ApiResponse.ts | 46 ++++++++++++++++++----- src/models/ApiResponseFactory.ts | 4 +- src/models/CreatedWithIdResponse.ts | 3 ++ src/models/DecimalRecordValue.ts | 9 +++++ src/models/DelegateListRecordValue.ts | 9 +++++ src/models/FileListRecordValue.ts | 9 +++++ src/models/GetRecordsByAppIdRequest.ts | 3 ++ src/models/GuidListRecordValue.ts | 9 +++++ src/models/GuidRecordValue.ts | 9 +++++ src/models/IntegerListRecordValue.ts | 9 +++++ src/models/OnspringClient.ts | 18 ++++++++- src/models/QueryFilter.ts | 26 +++++++++++++ src/models/Record.ts | 4 ++ src/models/SaveRecordResponse.ts | 12 ++++++ src/models/ScoringGroupListRecordValue.ts | 9 +++++ src/models/StringListRecordValue.ts | 9 +++++ src/models/TimeSpanRecordValue.ts | 9 +++++ 17 files changed, 185 insertions(+), 12 deletions(-) diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index be44d7d..db78f0a 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -92,17 +92,17 @@ export class ApiResponse { public asGetPagedAppsResponseType(): ApiResponse { const apiResponse = this as ApiResponse; -const apps = apiResponse.data.items.map((item: any) => { - return new App(item.href, item.id, item.name); -}); + const apps = apiResponse.data.items.map((item: any) => { + return new App(item.href, item.id, item.name); + }); -const getAppsPagedResponse = new GetPagedAppsResponse( - apps, - apiResponse.data.pageNumber, - apiResponse.data.pageSize, - apiResponse.data.totalPages, - apiResponse.data.totalRecords -); + const getAppsPagedResponse = new GetPagedAppsResponse( + apps, + apiResponse.data.pageNumber, + apiResponse.data.pageSize, + apiResponse.data.totalPages, + apiResponse.data.totalRecords + ); return new ApiResponse( apiResponse.statusCode, @@ -238,6 +238,10 @@ const getAppsPagedResponse = new GetPagedAppsResponse( ); } + /** + * @method asFileInfoType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asFileInfoType(): ApiResponse { const apiResponse = this as ApiResponse; @@ -259,6 +263,10 @@ const getAppsPagedResponse = new GetPagedAppsResponse( ); } + /** + * @method asFileType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asFileType(response: AxiosResponse): ApiResponse { const apiResponse = this as ApiResponse; @@ -411,6 +419,10 @@ const getAppsPagedResponse = new GetPagedAppsResponse( ); } + /** + * @method asRecordCollectionType - Converts the ApiResponse to an ApiResponse>. + * @returns {ApiResponse>} - An ApiResponse>. + */ public asRecordCollectionType(): ApiResponse> { const apiResponse = this as ApiResponse; @@ -434,6 +446,10 @@ const getAppsPagedResponse = new GetPagedAppsResponse( ); } + /** + * @method asSaveRecordResponseType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asSaveRecordResponseType(): ApiResponse { const apiResponse = this as ApiResponse; const response = new SaveRecordResponse( @@ -447,6 +463,11 @@ const getAppsPagedResponse = new GetPagedAppsResponse( ); } + /** + * @method getRecordValueByType - Gets the RecordValue by by type. + * @param {RecordValue} recordValueItem - The record value item. + * @returns {RecordValue} - The RecordValue. + */ private static getRecordValueByType(recordValueItem: any): RecordValue { const type = RecordValueType[recordValueItem.type]; @@ -629,6 +650,11 @@ const getAppsPagedResponse = new GetPagedAppsResponse( } } + /** + * @method convertToDelegate - Converts the delegate item to a Delegate object. + * @param {any} delegateItem - The delegate item to convert. + * @returns {Delegate} - The converted Delegate object. + */ private static convertToDelegate(delegateItem: any): Delegate { const delegateType = DelegateType[delegateItem.delegateType]; diff --git a/src/models/ApiResponseFactory.ts b/src/models/ApiResponseFactory.ts index f4cc601..5f0ee93 100644 --- a/src/models/ApiResponseFactory.ts +++ b/src/models/ApiResponseFactory.ts @@ -60,7 +60,9 @@ export class ApiResponseFactory { } /** - * + * @method getStreamDataAsString - Gets the data from a stream as a string + * @param {Readable} stream - The stream that will be used to get the data + * @returns {Promise} - A promise that resolves to the data from the stream as a string */ private static async getStreamDataAsString( stream: Readable diff --git a/src/models/CreatedWithIdResponse.ts b/src/models/CreatedWithIdResponse.ts index 9907e65..993acaa 100644 --- a/src/models/CreatedWithIdResponse.ts +++ b/src/models/CreatedWithIdResponse.ts @@ -1,3 +1,6 @@ +/** + * @class CreatedWithIdResponse - Represents a response to a request to create a resource. + */ export class CreatedWithIdResponse { /** * @property {T} id - The id of the created object. diff --git a/src/models/DecimalRecordValue.ts b/src/models/DecimalRecordValue.ts index 38d206b..455799c 100644 --- a/src/models/DecimalRecordValue.ts +++ b/src/models/DecimalRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValue } from './RecordValue'; import { RecordValueType } from '../enums/RecordValueType'; +/** + * @class DecimalRecordValue - Represents a decimal record value + */ export class DecimalRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of DecimalRecordValue + * @param {number} fieldId - The id of the field + * @param {number} value - The value of the field + * @returns {DecimalRecordValue} - A new instance of DecimalRecordValue + */ constructor(fieldId: number, value: number) { super(RecordValueType.Decimal, fieldId, value); } diff --git a/src/models/DelegateListRecordValue.ts b/src/models/DelegateListRecordValue.ts index 1ac9a6f..adc61ce 100644 --- a/src/models/DelegateListRecordValue.ts +++ b/src/models/DelegateListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValue } from './RecordValue'; import { RecordValueType } from '../enums/RecordValueType'; import { type Delegate } from './Delegate'; +/** + * @class DelegateListRecordValue - Represents a delegate list record value. + */ export class DelegateListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of DelegateListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {Delegate[]} value - The value of the field. + * @returns {DelegateListRecordValue} - A new instance of DelegateListRecordValue. + */ constructor(fieldId: number, value: Delegate[]) { super(RecordValueType.DelegateList, fieldId, value); } diff --git a/src/models/FileListRecordValue.ts b/src/models/FileListRecordValue.ts index bd49bc5..247ae64 100644 --- a/src/models/FileListRecordValue.ts +++ b/src/models/FileListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValue } from './RecordValue'; import { RecordValueType } from '../enums/RecordValueType'; import { type File } from './File'; +/** + * @class FileListRecordValue - Represents a file list record value. + */ export class FileListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of FileListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {File[]} value - The value of the field. + * @returns {FileListRecordValue} - A new instance of FileListRecordValue. + */ constructor(fieldId: number, value: File[]) { super(RecordValueType.FileList, fieldId, value); } diff --git a/src/models/GetRecordsByAppIdRequest.ts b/src/models/GetRecordsByAppIdRequest.ts index b49435b..b7e4ecc 100644 --- a/src/models/GetRecordsByAppIdRequest.ts +++ b/src/models/GetRecordsByAppIdRequest.ts @@ -1,6 +1,9 @@ import { DataFormat } from '../enums/DataFormat'; import { PagingRequest } from './PagingRequest'; +/** + * @class GetRecordsByAppIdRequest - Represents a request to get records by app id. + */ export class GetRecordsByAppIdRequest { /** * @property {number} appId - The id of the app that the records belong to. diff --git a/src/models/GuidListRecordValue.ts b/src/models/GuidListRecordValue.ts index 7e9a064..7b33f30 100644 --- a/src/models/GuidListRecordValue.ts +++ b/src/models/GuidListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; +/** + * @class GuidListRecordValue - Represents a guid list record value. + */ export class GuidListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of GuidListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string[]} value - The value of the field. + * @returns {GuidListRecordValue} - A new instance of GuidListRecordValue. + */ constructor(fieldId: number, value: string[]) { super(RecordValueType.GuidList, fieldId, value); } diff --git a/src/models/GuidRecordValue.ts b/src/models/GuidRecordValue.ts index 9af101c..ae4e9b9 100644 --- a/src/models/GuidRecordValue.ts +++ b/src/models/GuidRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; +/** + * @class GuidRecordValue - Represents a guid record value. + */ export class GuidRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of GuidRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string} value - The value of the field. + * @returns {GuidRecordValue} - A new instance of GuidRecordValue. + */ constructor(fieldId: number, value: string) { super(RecordValueType.Guid, fieldId, value); } diff --git a/src/models/IntegerListRecordValue.ts b/src/models/IntegerListRecordValue.ts index 0fce22b..439b408 100644 --- a/src/models/IntegerListRecordValue.ts +++ b/src/models/IntegerListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; +/** + * @class IntegerListRecordValue - Represents an integer list record value. + */ export class IntegerListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of IntegerListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {number[]} value - The value of the field. + * @returns {IntegerListRecordValue} - A new instance of IntegerListRecordValue. + */ constructor(fieldId: number, value: number[]) { super(RecordValueType.IntegerList, fieldId, value); } diff --git a/src/models/OnspringClient.ts b/src/models/OnspringClient.ts index 2b58b6a..ff2f1ec 100644 --- a/src/models/OnspringClient.ts +++ b/src/models/OnspringClient.ts @@ -49,7 +49,11 @@ export class OnspringClient { * @throws {Error} - Thrown when the apiKey is null/undefined/empty/whitespace. * @returns {OnspringClient} - A new instance of the OnspringClient class. */ - constructor(baseUrl: string | undefined | null, apiKey: string | undefined | null, config: CreateAxiosDefaults = {}) { + constructor( + baseUrl: string | undefined | null, + apiKey: string | undefined | null, + config: CreateAxiosDefaults = {} + ) { if (ArgumentValidator.isValidUrl(baseUrl) === false || baseUrl === null) { throw new Error('baseUrl must be an absolute and well-formed URI.'); } @@ -278,6 +282,13 @@ export class OnspringClient { return apiResponse.asCreatedWithIdResponseType(); } + /** + * @method deleteFileById - Deletes a file by its id. + * @param {number} recordId - The id of the record that the file is held on. + * @param {number} fieldId - The id of the field that the file is held in. + * @param {number} fileId - The id of the file to delete. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type any. + */ public async deleteFileById( recordId: number, fieldId: number, @@ -412,6 +423,11 @@ export class OnspringClient { return apiResponse.asGetPagedRecordsResponseType(); } + /** + * @method saveRecord - Saves a record. + * @param {Record | SaveRecordRequest} request - The record or request that will be used to save the record. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type SaveRecordResponse. + */ public async saveRecord( request: Record | SaveRecordRequest ): Promise> { diff --git a/src/models/QueryFilter.ts b/src/models/QueryFilter.ts index 8bc6e49..6ea0c06 100644 --- a/src/models/QueryFilter.ts +++ b/src/models/QueryFilter.ts @@ -1,10 +1,32 @@ import { FilterOperators } from '../enums/FilterOperators'; +/** + * @class QueryFilter - Represents a query filter. + */ export class QueryFilter { + /** + * @property {number} fieldId - The id of the field to filter on. + */ public fieldId: number; + + /** + * @property {FilterOperators} operator - The operator for the filter. + */ public operator: FilterOperators; + + /** + * @property {string | number | Date | null} value - The value for the filter. + */ public value: string | number | Date | null; + /** + * @constructor - Creates a new instance of the QueryFilter class. + * @param {number} fieldId - The id of the field to filter on. + * @param {FilterOperators} operator - The operator for the filter. + * @param {string | number | Date | null} value - The value for the filter. + * @returns {QueryFilter} - A new instance of the QueryFilter class. + * @throws {Error} - If the value is null and the operator is not IsNull or NotNull. + */ constructor( fieldId: number, operator: FilterOperators, @@ -23,6 +45,10 @@ export class QueryFilter { this.value = value; } + /** + * @method toString - Converts the filter to a string. + * @returns {string} - The filter as a string. + */ public toString(): string { if (this.value == null) { return `${this.fieldId} ${this.operator}`; diff --git a/src/models/Record.ts b/src/models/Record.ts index 92a804b..c2e1307 100644 --- a/src/models/Record.ts +++ b/src/models/Record.ts @@ -55,6 +55,10 @@ export class Record { this.fieldData = this.fieldData.concat(fieldData); } + /** + * @method convertToSaveRecordRequest - Converts the record to a SaveRecordRequest. + * @returns {SaveRecordRequest} - A SaveRecordRequest. + */ public convertToSaveRecordRequest(): SaveRecordRequest { const fields = this.fieldData.reduce((acc, cur) => { acc.set(cur.fieldId, cur.value); diff --git a/src/models/SaveRecordResponse.ts b/src/models/SaveRecordResponse.ts index ad70380..28086e0 100644 --- a/src/models/SaveRecordResponse.ts +++ b/src/models/SaveRecordResponse.ts @@ -1,8 +1,20 @@ import { CreatedWithIdResponse } from './CreatedWithIdResponse'; +/** + * @class SaveRecordResponse - Response from saving a record + */ export class SaveRecordResponse extends CreatedWithIdResponse { + /** + * @property {string[]} warnings - The warnings from saving the record. + */ public warnings: string[]; + /** + * @constructor - Creates a new instance of SaveRecordResponse. + * @param {number} id - The id of the record. + * @param {string[]} warnings - The warnings from saving the record. + * @returns {SaveRecordResponse} - A new instance of SaveRecordResponse.s + */ constructor(id: number, warnings: string[] = []) { super(id); this.warnings = warnings; diff --git a/src/models/ScoringGroupListRecordValue.ts b/src/models/ScoringGroupListRecordValue.ts index 67b4859..9bd3e2a 100644 --- a/src/models/ScoringGroupListRecordValue.ts +++ b/src/models/ScoringGroupListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; import { type ScoringGroup } from './ScoringGroup'; +/** + * @class ScoringGroupListRecordValue - Represents a scoring group list record value. + */ export class ScoringGroupListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of ScoringGroupListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {ScoringGroup[]} value - The value of the field. + * @returns {ScoringGroupListRecordValue} - A new instance of ScoringGroupListRecordValue. + */ constructor(fieldId: number, value: ScoringGroup[]) { super(RecordValueType.ScoringGroupList, fieldId, value); } diff --git a/src/models/StringListRecordValue.ts b/src/models/StringListRecordValue.ts index 674dadb..430c904 100644 --- a/src/models/StringListRecordValue.ts +++ b/src/models/StringListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; +/** + * @class StringListRecordValue - Represents a string list record value. + */ export class StringListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of StringListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string[]} value - The value of the field. + * @returns {StringListRecordValue} - A new instance of StringListRecordValue. + */ constructor(fieldId: number, value: string[]) { super(RecordValueType.StringList, fieldId, value); } diff --git a/src/models/TimeSpanRecordValue.ts b/src/models/TimeSpanRecordValue.ts index cead1dc..d729942 100644 --- a/src/models/TimeSpanRecordValue.ts +++ b/src/models/TimeSpanRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType'; import { RecordValue } from './RecordValue'; import { type TimeSpanData } from './TimeSpanData'; +/** + * @class TimeSpanRecordValue - Represents a time span record value. + */ export class TimeSpanRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of TimeSpanRecordValue. + * @param {number} fieldId - The id of the field. + * @param {TimeSpanData} value - The value of the field. + * @returns {TimeSpanRecordValue} - A new instance of TimeSpanRecordValue. + */ constructor(fieldId: number, value: TimeSpanData) { super(RecordValueType.TimeSpan, fieldId, value); } From f48189a88106dff2f2b77219bd2e3c4e2c15cb8c Mon Sep 17 00:00:00 2001 From: StevanFreeborn <=> Date: Tue, 21 Feb 2023 08:59:14 -0600 Subject: [PATCH 03/23] docs: stub out README.md --- README.md | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df38cc3..4f18195 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,319 @@ [![build_publish](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml/badge.svg?branch=master)](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml) [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release) -A javascript SDK for interacting with version 2 of the Onspring API. +The javascript SDK for the Onspring API is meant to simplify development in Javascript 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 Javascript with an Onspring instance quicker and more convenient. + +## Dependencies + +### Node.js + +Requires use of Node 14.x or later. + +### Axios + +All methods for the `OnspringClient` make use of the [Axios](https://axios-http.com/) http client to interact with the Onspring API. + +### Form-Data + +When it is necessary to send requests to the Onspring API using `multi-part/form-data` the [Form-Data](https://www.npmjs.com/package/form-data) package is used. + +## Installation + +Install the SDK using npm: + +`npm install onspring-api-sdk` + +## 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: + +- `baseUrl` - currently this should always be: `https://api.onspring.com` +- `apiKey` - 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 `.env` file: + +```env +API_KEY=000000ffffff000000ffffff/00000000-ffff-0000-ffff-000000000000 +BASE_URL=https://api.onspring.com +``` + +Example constructing `OnspringClient`: + +`CommonJS` + +```js + +``` + +`ES Module` + +```js + +``` + +### `ApiResponse` + +Each `OnspringClient` method - aside from `canConnect` - returns an `ApiResponse` object which will have the following properties: + +- `statusCode` - The http status code of the response. +- `isSuccessful` - Indicates whether the request succeeded. +- `data` - If the request was successful will contain the response data deserialized to custom classes. +- `message` - A message that may provide more detail about the request when no successful + +## CommonJS or ES Modules + +There is support for using either CommonJS or ES Modules depending upon your preference. This documentation will use the later in the usage examples. + +## Types + +The package is written in typescript and all types are exported and availabe for you to use if you prefer to use typescript. + +## Full API Documentation + +You may wish to refer to the full [Onspring API documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) when determining which values to pass as parameters to some of the `OnspringClient` methods. There is also a [swagger page](https://api.onspring.com/swagger/index.html) that you can use for making exploratory requests. + +### Connectivity + +#### Verify connectivity + +```js + +``` + +### 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. + +```js + +``` + +You can set your own page size and page number (max is 1,000) as well. + +```js + +``` + +#### Get App By Id + +Returns an Onspring app or survey according to provided id. + +```js + +``` + +#### Get Apps By Ids + +Returns a collection of Onspring apps and/or surveys according to provided ids. + +```js + +``` + +### Fields + +#### Get Field By Id + +Returns an Onspring field according to provided id. + +```js + +``` + +#### Get Fields By Ids + +Returns a collection of Onspring fields according to provided ids. + +```js + +``` + +#### 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. + +```js + +``` + +You can set your own page size and page number (max is 1,000) as well. + +```js + +``` + +### Files + +#### Get File Info By Id + +Returns the Onspring file's metadata. + +```js + +``` + +#### Get File By Id + +Returns the file itself. + +```js + +``` + +#### Save File + +```js + +``` + +#### Delete File By Id + +```js + +``` + +### Lists + +#### Add Or Update List Value + +To add a list value don't provide an id value. + +```js + +``` + +To update a list value provide an id value. + +```js + +``` + +#### Delete List Value + +```js + +``` + +### Records + +#### Get Records By App Id + +Returns a paged colletion of records that can be paged through. By default the page size is 50 and page number is 1. + +```js + +``` + +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. + +```js + +``` + +#### Get Record By Id + +Returns an onspring record based on the provided app and record ids. + +```js + +``` + +You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. + +```js + +``` + +#### Get Records By Ids + +Returns a collection of Onspring records based on the provided appId and recordIds. + +```js + +``` + +You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. + +```js + +``` + +#### Query Records + +Returns a paged colletion of records based on a criteria that can be paged through. By default the page size is 50 and page number is 1. + +```js + +``` + +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. + +```js + +``` + +For further details on constructing the `filter` parameter please refer to the [documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) 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. + +```js + +``` + +You can update a record by providing its id. If successful will return the id of record updated. + +```js + +``` + +#### Delete Records By Ids + +```js + +``` + +### Reports + +#### Get Report By Id + +Returns the report for the provided id. + +```js + +``` + +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. + +```js + +``` + +#### 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. + +```js + +``` From e97ee153870250440e2e0760ac9e88f6f4f98856 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 20 Feb 2023 19:12:15 -0600 Subject: [PATCH 04/23] fix: update jsdoc comments for enums --- src/enums/DelegateType.ts | 20 ++++++++++++++++---- src/enums/FileStorageSite.ts | 3 +++ src/enums/FilterOperators.ts | 10 ++++++++++ src/enums/FormulaOutputType.ts | 3 +++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/enums/DelegateType.ts b/src/enums/DelegateType.ts index 5a8c529..57e23fa 100644 --- a/src/enums/DelegateType.ts +++ b/src/enums/DelegateType.ts @@ -1,4 +1,16 @@ -export enum DelegateType { - External = 'External', - Internal = 'Internal', -} +/** + * @enum DelegateType - The type of delegate + */ +export enum DelegateType { + /** + * @constant External - The delegate is external. + * @type {string} + */ + External = 'External', + + /** + * @constant Internal - The delegate is internal. + * @type {string} + */ + Internal = 'Internal', +} diff --git a/src/enums/FileStorageSite.ts b/src/enums/FileStorageSite.ts index 34883a1..bf13da4 100644 --- a/src/enums/FileStorageSite.ts +++ b/src/enums/FileStorageSite.ts @@ -1,3 +1,6 @@ +/** + * @enum FileStorageSite - The site where the file is stored. + */ export enum FileStorageSite { /** * @constant Internal - The file is stored in the internal file storage. diff --git a/src/enums/FilterOperators.ts b/src/enums/FilterOperators.ts index 5210291..b66d368 100644 --- a/src/enums/FilterOperators.ts +++ b/src/enums/FilterOperators.ts @@ -4,60 +4,70 @@ export enum FilterOperators { /** * @constant Equal - The equal operator + * @type {string} * @remarks Can be used with text, auto-number, date, and number fields as well as their formula equivalents. */ Equal = 'eq', /** * @constant NotEqual - The not equal operator + * @type {string} * @remarks Can be used with text, auto-number, date, and number fields as well as their formula equivalents. */ NotEqual = 'ne', /** * @constant Contains - The contains operator + * @type {string} * @remarks Can be used with list fields as well as their formula equivalents. */ Contains = 'contains', /** * @constant IsNull - The is null operator + * @type {string} * @remarks Can be used with text, date, and number fields as well as their formula equivalents. */ IsNull = 'isnull', /** * @constant NotNull - The not null operator + * @type {string} * @remarks Can be used with text, date, and number fields as well as their formula equivalents. */ NotNull = 'notnull', /** * @constant GreaterThan - The greater than operator + * @type {string} * @remarks Can be used with auto-number, date, and number fields as well as their formula equivalents. */ GreaterThan = 'gt', /** * @constant LessThan - The less than operator + * @type {string} * @remarks Can be used with auto-number, date, and number fields as well as their formula equivalents. */ LessThan = 'lt', /** * @constant And - The and operator + * @type {string} * @remarks Can be used to create compound filters. */ And = 'and', /** * @constant Or - The or operator + * @type {string} * @remarks Can be used to create compound filters. */ Or = 'or', /** * @constant Not - The not operator + * @type {string} * @remarks Can be used to negate a filter and create compound filters. */ Not = 'not', diff --git a/src/enums/FormulaOutputType.ts b/src/enums/FormulaOutputType.ts index ca7c9b8..5de8038 100644 --- a/src/enums/FormulaOutputType.ts +++ b/src/enums/FormulaOutputType.ts @@ -1,3 +1,6 @@ +/** + * @enum FormulaOutputType - The type of the formula output. + */ export enum FormulaOutputType { /** * @constant Text - The formula output is a text value. From 07ec44a0ad4f58f273b9448fc7010d1dbef2265c Mon Sep 17 00:00:00 2001 From: StevanFreeborn <=> Date: Mon, 20 Feb 2023 21:08:22 -0600 Subject: [PATCH 05/23] fix: add jsdoc comments to models --- src/models/ApiResponse.ts | 26 +++++++++++++++++++++++ src/models/ApiResponseFactory.ts | 4 +++- src/models/CreatedWithIdResponse.ts | 3 +++ src/models/DecimalRecordValue.ts | 9 ++++++++ src/models/DelegateListRecordValue.ts | 9 ++++++++ src/models/FileListRecordValue.ts | 9 ++++++++ src/models/GetRecordsByAppIdRequest.ts | 3 +++ src/models/GuidListRecordValue.ts | 9 ++++++++ src/models/GuidRecordValue.ts | 9 ++++++++ src/models/IntegerListRecordValue.ts | 9 ++++++++ src/models/OnspringClient.ts | 12 +++++++++++ src/models/QueryFilter.ts | 26 +++++++++++++++++++++++ src/models/Record.ts | 4 ++++ src/models/SaveRecordResponse.ts | 12 +++++++++++ src/models/ScoringGroupListRecordValue.ts | 9 ++++++++ src/models/StringListRecordValue.ts | 9 ++++++++ src/models/TimeSpanRecordValue.ts | 9 ++++++++ 17 files changed, 170 insertions(+), 1 deletion(-) diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index aae1260..cf42ac1 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -238,6 +238,10 @@ export class ApiResponse { ); } + /** + * @method asFileInfoType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asFileInfoType(): ApiResponse { const apiResponse = this as ApiResponse; @@ -259,6 +263,10 @@ export class ApiResponse { ); } + /** + * @method asFileType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asFileType(response: AxiosResponse): ApiResponse { const apiResponse = this as ApiResponse; @@ -411,6 +419,10 @@ export class ApiResponse { ); } + /** + * @method asRecordCollectionType - Converts the ApiResponse to an ApiResponse>. + * @returns {ApiResponse>} - An ApiResponse>. + */ public asRecordCollectionType(): ApiResponse> { const apiResponse = this as ApiResponse; @@ -434,6 +446,10 @@ export class ApiResponse { ); } + /** + * @method asSaveRecordResponseType - Converts the ApiResponse to an ApiResponse. + * @returns {ApiResponse} - An ApiResponse. + */ public asSaveRecordResponseType(): ApiResponse { const apiResponse = this as ApiResponse; const response = new SaveRecordResponse( @@ -447,6 +463,11 @@ export class ApiResponse { ); } + /** + * @method getRecordValueByType - Gets the RecordValue by by type. + * @param {RecordValue} recordValueItem - The record value item. + * @returns {RecordValue} - The RecordValue. + */ private static getRecordValueByType(recordValueItem: any): RecordValue { const type = RecordValueType[recordValueItem.type]; @@ -629,6 +650,11 @@ export class ApiResponse { } } + /** + * @method convertToDelegate - Converts the delegate item to a Delegate object. + * @param {any} delegateItem - The delegate item to convert. + * @returns {Delegate} - The converted Delegate object. + */ private static convertToDelegate(delegateItem: any): Delegate { const delegateType = DelegateType[delegateItem.delegateType]; diff --git a/src/models/ApiResponseFactory.ts b/src/models/ApiResponseFactory.ts index 054751a..91292a2 100644 --- a/src/models/ApiResponseFactory.ts +++ b/src/models/ApiResponseFactory.ts @@ -60,7 +60,9 @@ export class ApiResponseFactory { } /** - * + * @method getStreamDataAsString - Gets the data from a stream as a string + * @param {Readable} stream - The stream that will be used to get the data + * @returns {Promise} - A promise that resolves to the data from the stream as a string */ private static async getStreamDataAsString( stream: Readable diff --git a/src/models/CreatedWithIdResponse.ts b/src/models/CreatedWithIdResponse.ts index 9907e65..993acaa 100644 --- a/src/models/CreatedWithIdResponse.ts +++ b/src/models/CreatedWithIdResponse.ts @@ -1,3 +1,6 @@ +/** + * @class CreatedWithIdResponse - Represents a response to a request to create a resource. + */ export class CreatedWithIdResponse { /** * @property {T} id - The id of the created object. diff --git a/src/models/DecimalRecordValue.ts b/src/models/DecimalRecordValue.ts index 06f45df..3c11e7d 100644 --- a/src/models/DecimalRecordValue.ts +++ b/src/models/DecimalRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValue } from './RecordValue.js'; import { RecordValueType } from '../enums/RecordValueType.js'; +/** + * @class DecimalRecordValue - Represents a decimal record value + */ export class DecimalRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of DecimalRecordValue + * @param {number} fieldId - The id of the field + * @param {number} value - The value of the field + * @returns {DecimalRecordValue} - A new instance of DecimalRecordValue + */ constructor(fieldId: number, value: number) { super(RecordValueType.Decimal, fieldId, value); } diff --git a/src/models/DelegateListRecordValue.ts b/src/models/DelegateListRecordValue.ts index 335d7c7..f8ffc85 100644 --- a/src/models/DelegateListRecordValue.ts +++ b/src/models/DelegateListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { type Delegate } from './Delegate.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class DelegateListRecordValue - Represents a delegate list record value. + */ export class DelegateListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of DelegateListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {Delegate[]} value - The value of the field. + * @returns {DelegateListRecordValue} - A new instance of DelegateListRecordValue. + */ constructor(fieldId: number, value: Delegate[]) { super(RecordValueType.DelegateList, fieldId, value); } diff --git a/src/models/FileListRecordValue.ts b/src/models/FileListRecordValue.ts index c2b18b1..39e1bf2 100644 --- a/src/models/FileListRecordValue.ts +++ b/src/models/FileListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { type File } from './File.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class FileListRecordValue - Represents a file list record value. + */ export class FileListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of FileListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {File[]} value - The value of the field. + * @returns {FileListRecordValue} - A new instance of FileListRecordValue. + */ constructor(fieldId: number, value: File[]) { super(RecordValueType.FileList, fieldId, value); } diff --git a/src/models/GetRecordsByAppIdRequest.ts b/src/models/GetRecordsByAppIdRequest.ts index 993b616..91d51be 100644 --- a/src/models/GetRecordsByAppIdRequest.ts +++ b/src/models/GetRecordsByAppIdRequest.ts @@ -1,6 +1,9 @@ import { DataFormat } from '../enums/DataFormat.js'; import { PagingRequest } from './PagingRequest.js'; +/** + * @class GetRecordsByAppIdRequest - Represents a request to get records by app id. + */ export class GetRecordsByAppIdRequest { /** * @property {number} appId - The id of the app that the records belong to. diff --git a/src/models/GuidListRecordValue.ts b/src/models/GuidListRecordValue.ts index fa61a6f..b27b15d 100644 --- a/src/models/GuidListRecordValue.ts +++ b/src/models/GuidListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class GuidListRecordValue - Represents a guid list record value. + */ export class GuidListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of GuidListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string[]} value - The value of the field. + * @returns {GuidListRecordValue} - A new instance of GuidListRecordValue. + */ constructor(fieldId: number, value: string[]) { super(RecordValueType.GuidList, fieldId, value); } diff --git a/src/models/GuidRecordValue.ts b/src/models/GuidRecordValue.ts index 354ed79..76f82c1 100644 --- a/src/models/GuidRecordValue.ts +++ b/src/models/GuidRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class GuidRecordValue - Represents a guid record value. + */ export class GuidRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of GuidRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string} value - The value of the field. + * @returns {GuidRecordValue} - A new instance of GuidRecordValue. + */ constructor(fieldId: number, value: string) { super(RecordValueType.Guid, fieldId, value); } diff --git a/src/models/IntegerListRecordValue.ts b/src/models/IntegerListRecordValue.ts index 7160477..963e486 100644 --- a/src/models/IntegerListRecordValue.ts +++ b/src/models/IntegerListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class IntegerListRecordValue - Represents an integer list record value. + */ export class IntegerListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of IntegerListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {number[]} value - The value of the field. + * @returns {IntegerListRecordValue} - A new instance of IntegerListRecordValue. + */ constructor(fieldId: number, value: number[]) { super(RecordValueType.IntegerList, fieldId, value); } diff --git a/src/models/OnspringClient.ts b/src/models/OnspringClient.ts index c57e623..a957bba 100644 --- a/src/models/OnspringClient.ts +++ b/src/models/OnspringClient.ts @@ -282,6 +282,13 @@ export class OnspringClient { return apiResponse.asCreatedWithIdResponseType(); } + /** + * @method deleteFileById - Deletes a file by its id. + * @param {number} recordId - The id of the record that the file is held on. + * @param {number} fieldId - The id of the field that the file is held in. + * @param {number} fileId - The id of the file to delete. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type any. + */ public async deleteFileById( recordId: number, fieldId: number, @@ -416,6 +423,11 @@ export class OnspringClient { return apiResponse.asGetPagedRecordsResponseType(); } + /** + * @method saveRecord - Saves a record. + * @param {Record | SaveRecordRequest} request - The record or request that will be used to save the record. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type SaveRecordResponse. + */ public async saveRecord( request: Record | SaveRecordRequest ): Promise> { diff --git a/src/models/QueryFilter.ts b/src/models/QueryFilter.ts index fbd49e1..6de4679 100644 --- a/src/models/QueryFilter.ts +++ b/src/models/QueryFilter.ts @@ -1,10 +1,32 @@ import { FilterOperators } from '../enums/FilterOperators.js'; +/** + * @class QueryFilter - Represents a query filter. + */ export class QueryFilter { + /** + * @property {number} fieldId - The id of the field to filter on. + */ public fieldId: number; + + /** + * @property {FilterOperators} operator - The operator for the filter. + */ public operator: FilterOperators; + + /** + * @property {string | number | Date | null} value - The value for the filter. + */ public value: string | number | Date | null; + /** + * @constructor - Creates a new instance of the QueryFilter class. + * @param {number} fieldId - The id of the field to filter on. + * @param {FilterOperators} operator - The operator for the filter. + * @param {string | number | Date | null} value - The value for the filter. + * @returns {QueryFilter} - A new instance of the QueryFilter class. + * @throws {Error} - If the value is null and the operator is not IsNull or NotNull. + */ constructor( fieldId: number, operator: FilterOperators, @@ -23,6 +45,10 @@ export class QueryFilter { this.value = value; } + /** + * @method toString - Converts the filter to a string. + * @returns {string} - The filter as a string. + */ public toString(): string { if (this.value == null) { return `${this.fieldId} ${this.operator}`; diff --git a/src/models/Record.ts b/src/models/Record.ts index 4379b50..929b6a6 100644 --- a/src/models/Record.ts +++ b/src/models/Record.ts @@ -55,6 +55,10 @@ export class Record { this.fieldData = this.fieldData.concat(fieldData); } + /** + * @method convertToSaveRecordRequest - Converts the record to a SaveRecordRequest. + * @returns {SaveRecordRequest} - A SaveRecordRequest. + */ public convertToSaveRecordRequest(): SaveRecordRequest { const fields = this.fieldData.reduce((acc, cur) => { acc.set(cur.fieldId, cur.value); diff --git a/src/models/SaveRecordResponse.ts b/src/models/SaveRecordResponse.ts index 8af03f0..b5a8cc2 100644 --- a/src/models/SaveRecordResponse.ts +++ b/src/models/SaveRecordResponse.ts @@ -1,8 +1,20 @@ import { CreatedWithIdResponse } from './CreatedWithIdResponse.js'; +/** + * @class SaveRecordResponse - Response from saving a record + */ export class SaveRecordResponse extends CreatedWithIdResponse { + /** + * @property {string[]} warnings - The warnings from saving the record. + */ public warnings: string[]; + /** + * @constructor - Creates a new instance of SaveRecordResponse. + * @param {number} id - The id of the record. + * @param {string[]} warnings - The warnings from saving the record. + * @returns {SaveRecordResponse} - A new instance of SaveRecordResponse.s + */ constructor(id: number, warnings: string[] = []) { super(id); this.warnings = warnings; diff --git a/src/models/ScoringGroupListRecordValue.ts b/src/models/ScoringGroupListRecordValue.ts index 39cd571..64318e7 100644 --- a/src/models/ScoringGroupListRecordValue.ts +++ b/src/models/ScoringGroupListRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; import { type ScoringGroup } from './ScoringGroup.js'; +/** + * @class ScoringGroupListRecordValue - Represents a scoring group list record value. + */ export class ScoringGroupListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of ScoringGroupListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {ScoringGroup[]} value - The value of the field. + * @returns {ScoringGroupListRecordValue} - A new instance of ScoringGroupListRecordValue. + */ constructor(fieldId: number, value: ScoringGroup[]) { super(RecordValueType.ScoringGroupList, fieldId, value); } diff --git a/src/models/StringListRecordValue.ts b/src/models/StringListRecordValue.ts index 943cf73..537c134 100644 --- a/src/models/StringListRecordValue.ts +++ b/src/models/StringListRecordValue.ts @@ -1,7 +1,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; +/** + * @class StringListRecordValue - Represents a string list record value. + */ export class StringListRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of StringListRecordValue. + * @param {number} fieldId - The id of the field. + * @param {string[]} value - The value of the field. + * @returns {StringListRecordValue} - A new instance of StringListRecordValue. + */ constructor(fieldId: number, value: string[]) { super(RecordValueType.StringList, fieldId, value); } diff --git a/src/models/TimeSpanRecordValue.ts b/src/models/TimeSpanRecordValue.ts index 186cba7..8b85272 100644 --- a/src/models/TimeSpanRecordValue.ts +++ b/src/models/TimeSpanRecordValue.ts @@ -2,7 +2,16 @@ import { RecordValueType } from '../enums/RecordValueType.js'; import { RecordValue } from './RecordValue.js'; import { type TimeSpanData } from './TimeSpanData.js'; +/** + * @class TimeSpanRecordValue - Represents a time span record value. + */ export class TimeSpanRecordValue extends RecordValue { + /** + * @constructor - Creates a new instance of TimeSpanRecordValue. + * @param {number} fieldId - The id of the field. + * @param {TimeSpanData} value - The value of the field. + * @returns {TimeSpanRecordValue} - A new instance of TimeSpanRecordValue. + */ constructor(fieldId: number, value: TimeSpanData) { super(RecordValueType.TimeSpan, fieldId, value); } From d8b6bf0b7b72f11a571e085ba59696a1d79282cd Mon Sep 17 00:00:00 2001 From: StevanFreeborn <=> Date: Tue, 21 Feb 2023 08:59:14 -0600 Subject: [PATCH 06/23] docs: stub out README.md --- README.md | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index df38cc3..4f18195 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,319 @@ [![build_publish](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml/badge.svg?branch=master)](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml) [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release) -A javascript SDK for interacting with version 2 of the Onspring API. +The javascript SDK for the Onspring API is meant to simplify development in Javascript 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 Javascript with an Onspring instance quicker and more convenient. + +## Dependencies + +### Node.js + +Requires use of Node 14.x or later. + +### Axios + +All methods for the `OnspringClient` make use of the [Axios](https://axios-http.com/) http client to interact with the Onspring API. + +### Form-Data + +When it is necessary to send requests to the Onspring API using `multi-part/form-data` the [Form-Data](https://www.npmjs.com/package/form-data) package is used. + +## Installation + +Install the SDK using npm: + +`npm install onspring-api-sdk` + +## 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: + +- `baseUrl` - currently this should always be: `https://api.onspring.com` +- `apiKey` - 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 `.env` file: + +```env +API_KEY=000000ffffff000000ffffff/00000000-ffff-0000-ffff-000000000000 +BASE_URL=https://api.onspring.com +``` + +Example constructing `OnspringClient`: + +`CommonJS` + +```js + +``` + +`ES Module` + +```js + +``` + +### `ApiResponse` + +Each `OnspringClient` method - aside from `canConnect` - returns an `ApiResponse` object which will have the following properties: + +- `statusCode` - The http status code of the response. +- `isSuccessful` - Indicates whether the request succeeded. +- `data` - If the request was successful will contain the response data deserialized to custom classes. +- `message` - A message that may provide more detail about the request when no successful + +## CommonJS or ES Modules + +There is support for using either CommonJS or ES Modules depending upon your preference. This documentation will use the later in the usage examples. + +## Types + +The package is written in typescript and all types are exported and availabe for you to use if you prefer to use typescript. + +## Full API Documentation + +You may wish to refer to the full [Onspring API documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) when determining which values to pass as parameters to some of the `OnspringClient` methods. There is also a [swagger page](https://api.onspring.com/swagger/index.html) that you can use for making exploratory requests. + +### Connectivity + +#### Verify connectivity + +```js + +``` + +### 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. + +```js + +``` + +You can set your own page size and page number (max is 1,000) as well. + +```js + +``` + +#### Get App By Id + +Returns an Onspring app or survey according to provided id. + +```js + +``` + +#### Get Apps By Ids + +Returns a collection of Onspring apps and/or surveys according to provided ids. + +```js + +``` + +### Fields + +#### Get Field By Id + +Returns an Onspring field according to provided id. + +```js + +``` + +#### Get Fields By Ids + +Returns a collection of Onspring fields according to provided ids. + +```js + +``` + +#### 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. + +```js + +``` + +You can set your own page size and page number (max is 1,000) as well. + +```js + +``` + +### Files + +#### Get File Info By Id + +Returns the Onspring file's metadata. + +```js + +``` + +#### Get File By Id + +Returns the file itself. + +```js + +``` + +#### Save File + +```js + +``` + +#### Delete File By Id + +```js + +``` + +### Lists + +#### Add Or Update List Value + +To add a list value don't provide an id value. + +```js + +``` + +To update a list value provide an id value. + +```js + +``` + +#### Delete List Value + +```js + +``` + +### Records + +#### Get Records By App Id + +Returns a paged colletion of records that can be paged through. By default the page size is 50 and page number is 1. + +```js + +``` + +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. + +```js + +``` + +#### Get Record By Id + +Returns an onspring record based on the provided app and record ids. + +```js + +``` + +You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. + +```js + +``` + +#### Get Records By Ids + +Returns a collection of Onspring records based on the provided appId and recordIds. + +```js + +``` + +You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. + +```js + +``` + +#### Query Records + +Returns a paged colletion of records based on a criteria that can be paged through. By default the page size is 50 and page number is 1. + +```js + +``` + +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. + +```js + +``` + +For further details on constructing the `filter` parameter please refer to the [documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) 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. + +```js + +``` + +You can update a record by providing its id. If successful will return the id of record updated. + +```js + +``` + +#### Delete Records By Ids + +```js + +``` + +### Reports + +#### Get Report By Id + +Returns the report for the provided id. + +```js + +``` + +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. + +```js + +``` + +#### 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. + +```js + +``` From dbdd3e18956f96f55c361d70a2d4172d9be4d79c Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 11:01:48 -0600 Subject: [PATCH 07/23] docs: begin working on code snippets --- README.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4f18195..785218b 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This SDK was developed independently using their existing C# SDK, their swagger ### Node.js -Requires use of Node 14.x or later. +Requires use of [Node.js](https://nodejs.org/en/) 14.x or later. ### Axios @@ -27,7 +27,7 @@ When it is necessary to send requests to the Onspring API using `multi-part/form ## Installation -Install the SDK using npm: +Install the SDK using [npm](https://www.npmjs.com/): `npm install onspring-api-sdk` @@ -64,11 +64,29 @@ Example constructing `OnspringClient`: `CommonJS` ```js +const { OnspringClient } = require('onspring-api-sdk'); +const dotenv = require('dotenv'); +dotenv.config(); +const client = new OnspringClient(process.env.BASE_URL, process.env.API_KEY); ``` `ES Module` +```js +import { OnspringClient } from 'onspring-api-sdk'; +import dotenv from 'dotenv'; +dotenv.config(); + +const client = new OnspringClient(process.env.BASE_URL, process.env.API_KEY); +``` + +#### Axios Instance Configuration + +By default when you construct an instance of the `OnspringClient` the a new `Axios` instance will also be created. Its `baseURL` property will always be set to the `baseUrl` parameter based to the `OnspringClient`'s constructor and its headers will always contain the proper `x-api-key` header. + +You can though pass a third optional argument to the `OnspringClient` constructor that specifies additional configuration options for the `Axios` instance used to make requests. + ```js ``` From d700c4fe4c4ba473584d7102ea98bba33b22da9f Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 14:28:02 -0600 Subject: [PATCH 08/23] docs: added example usages for canConnect, getApps, getAppById, and getAppsByIds methods --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index 785218b..a11bd24 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,10 @@ You may wish to refer to the full [Onspring API documentation](https://software. #### Verify connectivity ```js +import { client } from './onspringClient.mjs'; +const res = await client.canConnect(); +console.log(res); // true or false ``` ### Apps @@ -127,13 +130,29 @@ You may wish to refer to the full [Onspring API documentation](https://software. 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. ```js +const res = await client.getApps(); +const apps = res.data.items; +for (const app of apps) { + console.log(app.name); + console.log(app.id); + console.log(app.href); +} ``` You can set your own page size and page number (max is 1,000) as well. ```js +import { PagingRequest } from 'onspring-api-sdk'; +const res = await client.getApps(new PagingRequest(1, 1)); +const apps = res.data.items; + +for (const app of apps) { + console.log(app.name); + console.log(app.id); + console.log(app.href); +} ``` #### Get App By Id @@ -141,7 +160,12 @@ You can set your own page size and page number (max is 1,000) as well. Returns an Onspring app or survey according to provided id. ```js +const res = await client.getAppById(130); +const app = res.data; +console.log(app.name); +console.log(app.id); +console.log(app.href); ``` #### Get Apps By Ids @@ -149,7 +173,14 @@ Returns an Onspring app or survey according to provided id. Returns a collection of Onspring apps and/or surveys according to provided ids. ```js +const res = await client.getAppsByIds([130, 131]); +const apps = res.data.items; +for (const app of apps) { + console.log(app.name); + console.log(app.id); + console.log(app.href); +} ``` ### Fields From 77edd0a1faf0824b532ef8cec61c63950b7f0308 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 16:27:05 -0600 Subject: [PATCH 09/23] docs: add code examples to README.md + Added code example for configuring onspring client + Added code examples for field methods + Added code example for getFileInfoById method --- README.md | 61 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index a11bd24..66a5312 100644 --- a/README.md +++ b/README.md @@ -74,8 +74,8 @@ const client = new OnspringClient(process.env.BASE_URL, process.env.API_KEY); `ES Module` ```js -import { OnspringClient } from 'onspring-api-sdk'; import dotenv from 'dotenv'; +import { OnspringClient } from 'onspring-api-sdk'; dotenv.config(); const client = new OnspringClient(process.env.BASE_URL, process.env.API_KEY); @@ -88,7 +88,19 @@ By default when you construct an instance of the `OnspringClient` the a new `Axi You can though pass a third optional argument to the `OnspringClient` constructor that specifies additional configuration options for the `Axios` instance used to make requests. ```js +import dotenv from 'dotenv'; +import { OnspringClient } from 'onspring-api-sdk'; +dotenv.config(); +const configs = { + timeout: 5000, +}; + +const client = new OnspringClient( + process.env.BASE_URL, + process.env.API_KEY, + configs +); ``` ### `ApiResponse` @@ -106,7 +118,7 @@ There is support for using either CommonJS or ES Modules depending upon your pre ## Types -The package is written in typescript and all types are exported and availabe for you to use if you prefer to use typescript. +The package is written in typescript and all types are exported and available for you to use if you prefer to use typescript. ## Full API Documentation @@ -117,8 +129,6 @@ You may wish to refer to the full [Onspring API documentation](https://software. #### Verify connectivity ```js -import { client } from './onspringClient.mjs'; - const res = await client.canConnect(); console.log(res); // true or false ``` @@ -134,9 +144,7 @@ const res = await client.getApps(); const apps = res.data.items; for (const app of apps) { - console.log(app.name); - console.log(app.id); - console.log(app.href); + console.log(app); } ``` @@ -149,9 +157,7 @@ const res = await client.getApps(new PagingRequest(1, 1)); const apps = res.data.items; for (const app of apps) { - console.log(app.name); - console.log(app.id); - console.log(app.href); + console.log(app); } ``` @@ -163,9 +169,7 @@ Returns an Onspring app or survey according to provided id. const res = await client.getAppById(130); const app = res.data; -console.log(app.name); -console.log(app.id); -console.log(app.href); +console.log(app); ``` #### Get Apps By Ids @@ -177,9 +181,7 @@ const res = await client.getAppsByIds([130, 131]); const apps = res.data.items; for (const app of apps) { - console.log(app.name); - console.log(app.id); - console.log(app.href); + console.log(app); } ``` @@ -190,7 +192,10 @@ for (const app of apps) { Returns an Onspring field according to provided id. ```js +const res = await client.getFieldById(4793); +const field = res.data; +console.log(field); ``` #### Get Fields By Ids @@ -198,7 +203,12 @@ Returns an Onspring field according to provided id. Returns a collection of Onspring fields according to provided ids. ```js +const res = await client.getFieldsByIds([4793, 4801]); +const fields = res.data.items; +for (const field of fields) { + console.log(field); +} ``` #### Get Fields By App Id @@ -206,13 +216,25 @@ Returns a collection of Onspring fields according to provided ids. Returns a paged collection of fields that can be paged through. By default the page size is 50 and page number is 1. ```js +const res = await client.getFieldsByAppId(132); +const fields = res.data.items; +for (const field of fields) { + console.log(field); +} ``` You can set your own page size and page number (max is 1,000) as well. ```js +import { PagingRequest } from 'onspring-api-sdk'; +const res = await client.getFieldsByAppId(132, new PagingRequest(1, 1)); +const fields = res.data.items; + +for (const field of fields) { + console.log(field); +} ``` ### Files @@ -222,7 +244,10 @@ You can set your own page size and page number (max is 1,000) as well. Returns the Onspring file's metadata. ```js +const res = await client.getFileInfoById(1, 4806, 909); +const fileInfo = res.data; +console.log(fileInfo); ``` #### Get File By Id @@ -271,7 +296,7 @@ To update a list value provide an id value. #### Get Records By App Id -Returns a paged colletion of records that can be paged through. By default the page size is 50 and page number is 1. +Returns a paged collection of records that can be paged through. By default the page size is 50 and page number is 1. ```js @@ -313,7 +338,7 @@ You can also specify what field values to return and in what format (Raw vs. For #### Query Records -Returns a paged colletion of records based on a criteria that can be paged through. By default the page size is 50 and page number is 1. +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. ```js From ad9325a840f1da03774a89a2015470d6f5f04a7e Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 20:49:49 -0600 Subject: [PATCH 10/23] fix: finished updating README.md --- README.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 224 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 66a5312..3df5d14 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ [![codecov](https://codecov.io/github/StevanFreeborn/onspring-api-sdk-javascript/branch/master/graph/badge.svg?token=G1L3GKE0LV)](https://codecov.io/github/StevanFreeborn/onspring-api-sdk-javascript) [![build_publish](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml/badge.svg?branch=master)](https://github.com/StevanFreeborn/onspring-api-sdk-javascript/actions/workflows/build_publish.yml) [![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release) +[![NPM](https://img.shields.io/npm/l/onspring-api-sdk)](License.txt) +![npm](https://img.shields.io/npm/v/onspring-api-sdk) The javascript SDK for the Onspring API is meant to simplify development in Javascript for Onspring customers who want to build integrations with their Onspring instance. @@ -15,14 +17,20 @@ This SDK was developed independently using their existing C# SDK, their swagger ### Node.js +![node-current](https://img.shields.io/node/v/onspring-api-sdk) + Requires use of [Node.js](https://nodejs.org/en/) 14.x or later. ### Axios +![npm (prod) dependency version](https://img.shields.io/npm/dependency-version/onspring-api-sdk/axios) + All methods for the `OnspringClient` make use of the [Axios](https://axios-http.com/) http client to interact with the Onspring API. ### Form-Data +![npm (prod) dependency version](https://img.shields.io/npm/dependency-version/onspring-api-sdk/form-data) + When it is necessary to send requests to the Onspring API using `multi-part/form-data` the [Form-Data](https://www.npmjs.com/package/form-data) package is used. ## Installation @@ -118,12 +126,16 @@ There is support for using either CommonJS or ES Modules depending upon your pre ## Types -The package is written in typescript and all types are exported and available for you to use if you prefer to use typescript. +The package is written in typescript and all types are exported and available for you to use. ## Full API Documentation You may wish to refer to the full [Onspring API documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) when determining which values to pass as parameters to some of the `OnspringClient` methods. There is also a [swagger page](https://api.onspring.com/swagger/index.html) that you can use for making exploratory requests. +## Examples + +Note the following code snippets assume you've already instantiated an `OnspringClient` as shown in the [Start Coding](#start-coding) section. + ### Connectivity #### Verify connectivity @@ -255,19 +267,47 @@ console.log(fileInfo); Returns the file itself. ```js +import fs from 'fs'; +const res = await client.getFileById(1, 4806, 909); +const file = res.data; + +console.log(file.contentLength); +console.log(file.contentType); +console.log(file.fileName); +file.stream.pipe(fs.createWriteStream(file.fileName)); ``` #### Save File ```js +import fs from 'fs'; +import { SaveFileRequest } from 'onspring-api-sdk'; +const request = new SaveFileRequest( + 1, + 4806, + 'notes', + new Date(), + 'test-attachment.txt', + 'text/plain', + fs.createReadStream('test-attachment.txt') +); + +const res = await client.saveFile(request); +const fileId = res.data.id; + +console.log(fileId); ``` #### Delete File By Id ```js +const res = await client.deleteFileById(1, 4806, 1505); +res.statusCode === 204 + ? console.log('File deleted') + : console.log('Error deleting file'); ``` ### Lists @@ -277,19 +317,45 @@ Returns the file itself. To add a list value don't provide an id value. ```js +import { ListItemRequest } from 'onspring-api-sdk'; +const request = new ListItemRequest(638, null, 'New Value', 1, '#000000'); +const res = await client.addOrUpdateListItem(request); +const itemId = res.data.id; + +console.log(itemId); ``` To update a list value provide an id value. ```js +import { ListItemRequest } from 'onspring-api-sdk'; +const request = new ListItemRequest( + 638, + '35c79a46-04b8-4069-bbc1-161a175f962c', + 'Updated Value', + 1, + '#000000' +); + +const res = await client.addOrUpdateListItem(request); +const itemId = res.data.id; + +console.log(itemId); ``` #### Delete List Value ```js +const res = await client.deleteListItemById( + 638, + '35c79a46-04b8-4069-bbc1-161a175f962c' +); +res.statusCode === 204 + ? console.log('List item deleted') + : console.log('Error deleting list item'); ``` ### Records @@ -299,13 +365,39 @@ To update a list value provide an id value. Returns a paged collection of records that can be paged through. By default the page size is 50 and page number is 1. ```js +import { GetRecordsByAppIdRequest } from 'onspring-api-sdk'; +const request = new GetRecordsByAppIdRequest(130); +const res = await client.getRecordsByAppId(request); +const apps = res.data.items; + +for (const app of apps) { + console.log(app); +} ``` 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. ```js +import { + DataFormat, + GetRecordsByAppIdRequest, + PagingRequest, +} from 'onspring-api-sdk'; +const request = new GetRecordsByAppIdRequest( + 130, + [4804], + DataFormat.Raw, + new PagingRequest(1, 1) +); + +const res = await client.getRecordsByAppId(request); +const apps = res.data.items; + +for (const app of apps) { + console.log(app); +} ``` #### Get Record By Id @@ -313,13 +405,25 @@ You can set your own page size and page number (max is 1,000) as well. In additi Returns an onspring record based on the provided app and record ids. ```js +import { GetRecordRequest } from 'onspring-api-sdk'; +const request = new GetRecordRequest(130, 1); +const res = await client.getRecordById(request); +const record = res.data; + +console.log(record); ``` You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. ```js +import { DataFormat, GetRecordRequest } from 'onspring-api-sdk'; +const request = new GetRecordRequest(130, 1, [4804], DataFormat.Raw); +const res = await client.getRecordById(request); +const record = res.data; + +console.log(record); ``` #### Get Records By Ids @@ -327,13 +431,29 @@ You can also specify what field values to return and in what format (Raw vs. For Returns a collection of Onspring records based on the provided appId and recordIds. ```js +import { GetRecordsRequest } from 'onspring-api-sdk'; +const request = new GetRecordsRequest(130, [1]); +const res = await client.getRecordsByIds(request); +const records = res.data.items; + +for (const record of records) { + console.log(record); +} ``` You can also specify what field values to return and in what format (Raw vs. Formatted) to return them. ```js +import { DataFormat, GetRecordsRequest } from 'onspring-api-sdk'; +const request = new GetRecordsRequest(130, [1], [4804], DataFormat.Formatted); +const res = await client.getRecordsByIds(request); +const records = res.data.items; + +for (const record of records) { + console.log(record); +} ``` #### Query Records @@ -341,35 +461,106 @@ You can also specify what field values to return and in what format (Raw vs. For 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. ```js +import { + FilterOperators, + QueryFilter, + QueryRecordsRequest, +} from 'onspring-api-sdk'; +const filter = new QueryFilter(4745, FilterOperators.GreaterThan, 0); +const request = new QueryRecordsRequest(130, filter); +const res = await client.queryRecords(request); +const records = res.data.items; + +for (const record of records) { + console.log(record); +} ``` 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. ```js +import { + DataFormat, + FilterOperators, + PagingRequest, + QueryFilter, + QueryRecordsRequest, +} from 'onspring-api-sdk'; +const filter = new QueryFilter(4745, FilterOperators.GreaterThan, 0); +const request = new QueryRecordsRequest( + 130, + filter, + [4804], + DataFormat.Formatted, + new PagingRequest(1, 1) +); + +const res = await client.queryRecords(request); +const records = res.data.items; + +for (const record of records) { + console.log(record); +} ``` -For further details on constructing the `filter` parameter please refer to the [documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) for v2 of the Onspring API. +For further details on constructing the `filter` parameter please refer to the [documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) for 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. ```js +import { Record, StringRecordValue } from 'onspring-api-sdk'; +const record = new Record(130, null); +const fieldValue = new StringRecordValue(4804, 'Test'); +record.addValue(fieldValue); + +const res = await client.saveRecord(record); +const newRecordId = res.data.id; + +console.log(newRecordId); ``` You can update a record by providing its id. If successful will return the id of record updated. ```js +import { Record, StringRecordValue } from 'onspring-api-sdk'; +const record = new Record(130, 607); +const fieldValue = new StringRecordValue(4804, 'Updated'); +record.addValue(fieldValue); + +const res = await client.saveRecord(record); +const updatedRecordId = res.data.id; + +console.log(updatedRecordId); +``` + +#### Delete Record By Id + +Delete an individual record based upon its id. + +```js +const res = await client.deleteRecordById(130, 607); + +res.statusCode === 204 + ? console.log('Record deleted') + : console.log('Error deleting record'); ``` #### Delete Records By Ids -```js +Delete a batch of records based upon their ids. +```js +const res = await client.deleteRecordsByIds(130, [608, 609]); + +res.statusCode === 204 + ? console.log('Records deleted') + : console.log('Error deleting records'); ``` ### Reports @@ -379,13 +570,25 @@ You can update a record by providing its id. If successful will return the id of Returns the report for the provided id. ```js +const res = await client.getReportById(408); +const report = res.data; +console.log(report); ``` 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. ```js +import { DataFormat, ReportDataType } from 'onspring-api-sdk'; +const res = await client.getReportById( + 409, + DataFormat.Formatted, + ReportDataType.ChartData +); +const report = res.data; + +console.log(report); ``` #### Get Reports By App Id @@ -393,5 +596,23 @@ You can also specify the format of the data in the report as well as whether you Returns a paged collection of reports that can be paged through. By default the page size is 50 and page number is 1. ```js +const res = await client.getReportsByAppId(130); +const reports = res.data.items; +for (const report of reports) { + console.log(report); +} +``` + +You can set your own page size and page number (max is 1,000) as well. + +```js +import { PagingRequest } from 'onspring-api-sdk'; + +const res = await client.getReportsByAppId(130, new PagingRequest(1, 1)); +const reports = res.data.items; + +for (const report of reports) { + console.log(report); +} ``` From 0aa840873cb26ac0743b78afd8cecf1796914778 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:12:57 -0600 Subject: [PATCH 11/23] docs: update README.md --- README.md | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3df5d14..06d6c00 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@ [![NPM](https://img.shields.io/npm/l/onspring-api-sdk)](License.txt) ![npm](https://img.shields.io/npm/v/onspring-api-sdk) -The javascript SDK for the Onspring API is meant to simplify development in Javascript for Onspring customers who want to build integrations with their Onspring instance. +The Javascript SDK for the Onspring API is meant to simplify development in Javascript 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. +**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 Javascript with an Onspring instance quicker and more convenient. +This SDK was developed independently using Onspring's existing [C# SDK](https://github.com/onspring-technologies/onspring-api-sdk), the Onspring API's [swagger page](https://api.onspring.com/swagger/index.html), and [api documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) as the starting point with the intention of making development of integrations done in Javascript with an Onspring instance quicker and more convenient. -## Dependencies +## 🛠️ Dependencies ### Node.js @@ -33,13 +33,13 @@ All methods for the `OnspringClient` make use of the [Axios](https://axios-http. When it is necessary to send requests to the Onspring API using `multi-part/form-data` the [Form-Data](https://www.npmjs.com/package/form-data) package is used. -## Installation +## 💾 Installation Install the SDK using [npm](https://www.npmjs.com/): `npm install onspring-api-sdk` -## API Key +## 🔑 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: @@ -49,7 +49,16 @@ In order to successfully interact with the Onspring Api you will need an API key 4. Click on the **Developer Information** tab. 5. Copy the **X-ApiKey Header** value from this tab. -## Start Coding +**Important:** + +- An API Key must have a status of `Enabled` in order to make authorized requests. +- Each API Key must have an assigned Role. This role controls the permissions for requests made. If the API Key used does not have sufficient permissions the requests made won't be successful. + +### 🔒 Permission Considerations + +You can think of any API Key as another user in your Onspring instance and therefore it is subject to all the same permission considerations as any other user when it comes to its ability to access data in your instance. The API Key you use needs to have all the correct permissions within your instance to access the data requested. Things to think about in this context are `role security`, `content security`, and `field security`. + +## 🧑🏻‍💻 Start Coding ### `OnspringClient` @@ -89,7 +98,7 @@ dotenv.config(); const client = new OnspringClient(process.env.BASE_URL, process.env.API_KEY); ``` -#### Axios Instance Configuration +### `Axios` Instance Configuration By default when you construct an instance of the `OnspringClient` the a new `Axios` instance will also be created. Its `baseURL` property will always be set to the `baseUrl` parameter based to the `OnspringClient`'s constructor and its headers will always contain the proper `x-api-key` header. @@ -120,21 +129,21 @@ Each `OnspringClient` method - aside from `canConnect` - returns an `ApiResponse - `data` - If the request was successful will contain the response data deserialized to custom classes. - `message` - A message that may provide more detail about the request when no successful -## CommonJS or ES Modules +### CommonJS or ES Modules There is support for using either CommonJS or ES Modules depending upon your preference. This documentation will use the later in the usage examples. -## Types +### Types The package is written in typescript and all types are exported and available for you to use. -## Full API Documentation +### Full API Documentation You may wish to refer to the full [Onspring API documentation](https://software.onspring.com/hubfs/Training/Admin%20Guide%20-%20v2%20API.pdf) when determining which values to pass as parameters to some of the `OnspringClient` methods. There is also a [swagger page](https://api.onspring.com/swagger/index.html) that you can use for making exploratory requests. -## Examples +## 📋 Examples -Note the following code snippets assume you've already instantiated an `OnspringClient` as shown in the [Start Coding](#start-coding) section. +Note the following code snippets assume you've already instantiated an `OnspringClient` as shown in the [OnspringClient](#onspringclient) section. ### Connectivity From 0f58867c492194c03ee55cce1f704d37c5c88b65 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:13:51 -0600 Subject: [PATCH 12/23] fix: incorrectly spelled variable name corrected --- src/models/ApiResponse.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index 57c35e7..76cb555 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -738,7 +738,7 @@ export class ApiResponse { const hasRecurrence = timeSpanItem.recurrence !== null && timeSpanItem.recurrence !== undefined; - const recurrene = hasRecurrence + const recurrence = hasRecurrence ? TimeSpanRecurrenceType[timeSpanItem.recurrence] : null; @@ -761,7 +761,7 @@ export class ApiResponse { ); } - if (recurrene === undefined) { + if (recurrence === undefined) { throw new Error( `${ timeSpanItem.recurrence as string @@ -772,7 +772,7 @@ export class ApiResponse { return new TimeSpanData( timeSpanItem.quantity, increment, - recurrene, + recurrence, endAfterOccurrences, endByDate ); From 06ac0e91b0d54ac73b4e6d30e3491f5c8c7245fb Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:20:38 -0600 Subject: [PATCH 13/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index 6bbc4c3..4876345 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -120,3 +120,5 @@ jobs: steps: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 + with: + directory: ./coverage/ From bc44ed3a7afa16387484927c525c1f64bc61d2e0 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:34:45 -0600 Subject: [PATCH 14/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 4 +++- .nycrc | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index 4876345..f713587 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -121,4 +121,6 @@ jobs: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: - directory: ./coverage/ + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage-final.json + directory: ./coverage diff --git a/.nycrc b/.nycrc index f7ac663..978f10c 100644 --- a/.nycrc +++ b/.nycrc @@ -8,6 +8,6 @@ "all": true, "include": ["src/**/*.ts"], "exclude": ["src/index.ts", "**/*.spec.ts"], - "reporter": ["html", "lcov", "text", "text-summary"], + "reporter": ["html", "lcov", "text", "text-summary", "json"], "report-dir": "coverage" } From 5938f286030ffd9753bf10c1dade53743634eeea Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:40:56 -0600 Subject: [PATCH 15/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index f713587..ab37aba 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -113,11 +113,21 @@ jobs: TEST_SURVEY_ID: ${{ vars.TEST_SURVEY_ID }} TEST_SURVEY_RECORD_ID: ${{ vars.TEST_SURVEY_RECORD_ID }} TEST_TEXT_FIELD: ${{ vars.TEST_TEXT_FIELD }} + - name: Upload test coverage artifact + uses: actions/upload-artifact@v3.1.2 + with: + name: coverage + path: ./coverage publish_test_coverage: needs: test name: publish_test_coverage runs-on: ubuntu-latest steps: + - name: Download test coverage artifact + uses: actions/download-artifact@v3.0.2 + with: + name: coverage + path: ./coverage - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: From 74a1133e6f61227629157ff4199a3eb0c473a8f4 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:47:22 -0600 Subject: [PATCH 16/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index ab37aba..d2ff727 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -133,4 +133,4 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: ./coverage-final.json - directory: ./coverage + directory: ./coverage/ From 866774b5a580b6f66e41e9cb2c9abc033fa135fa Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:51:52 -0600 Subject: [PATCH 17/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index d2ff727..cb49be7 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -117,7 +117,7 @@ jobs: uses: actions/upload-artifact@v3.1.2 with: name: coverage - path: ./coverage + path: ./coverage/coverage-final.json publish_test_coverage: needs: test name: publish_test_coverage @@ -127,10 +127,9 @@ jobs: uses: actions/download-artifact@v3.0.2 with: name: coverage - path: ./coverage + path: ./coverage/coverage-final.json - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage-final.json - directory: ./coverage/ + files: ./coverage/coverage-final.json From 8930bc2777cfff40a9e7fe0bd96903a9f0cfb74d Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:58:01 -0600 Subject: [PATCH 18/23] chore: update publish_test_coverage job --- .github/workflows/lint_format_test.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index cb49be7..6d890a7 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -132,4 +132,6 @@ jobs: uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage/coverage-final.json + directory: ./coverage/ + files: ./coverage-final.json + verbose: true From 16fc7e2eae131f231e600da37f70ff6ac9b44b54 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:02:15 -0600 Subject: [PATCH 19/23] chore: more work on coverage job --- .github/workflows/lint_format_test.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index 6d890a7..9f138de 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -117,7 +117,7 @@ jobs: uses: actions/upload-artifact@v3.1.2 with: name: coverage - path: ./coverage/coverage-final.json + path: ./coverage publish_test_coverage: needs: test name: publish_test_coverage @@ -127,11 +127,8 @@ jobs: uses: actions/download-artifact@v3.0.2 with: name: coverage - path: ./coverage/coverage-final.json + path: ./coverage - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} - directory: ./coverage/ - files: ./coverage-final.json - verbose: true From 1bc524878147ea798fa15398a3d6a636fac87ddc Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:07:06 -0600 Subject: [PATCH 20/23] chore: more work on coverage job --- .nycrc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/.nycrc b/.nycrc index 978f10c..9b12abb 100644 --- a/.nycrc +++ b/.nycrc @@ -6,8 +6,18 @@ "functions": 100, "statements": 100, "all": true, - "include": ["src/**/*.ts"], - "exclude": ["src/index.ts", "**/*.spec.ts"], - "reporter": ["html", "lcov", "text", "text-summary", "json"], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/index.ts", + "**/*.spec.ts" + ], + "reporter": [ + "html", + "lcov", + "text", + "text-summary" + ], "report-dir": "coverage" -} +} \ No newline at end of file From f4125943385e8219b14c677769384b5e01077144 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:21:38 -0600 Subject: [PATCH 21/23] chore: update publish coverage job with step to checkout repo --- .github/workflows/lint_format_test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/lint_format_test.yaml b/.github/workflows/lint_format_test.yaml index 9f138de..ef795f1 100644 --- a/.github/workflows/lint_format_test.yaml +++ b/.github/workflows/lint_format_test.yaml @@ -123,6 +123,8 @@ jobs: name: publish_test_coverage runs-on: ubuntu-latest steps: + - name: Check out repository + uses: actions/checkout@v3 - name: Download test coverage artifact uses: actions/download-artifact@v3.0.2 with: From 9ff9f24d855cdb3326cec31a4c71e101ee59c6d1 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:25:27 -0600 Subject: [PATCH 22/23] chore: update husky commit-msg --- .husky/commit-msg | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .husky/commit-msg diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 From eac881ec589a590ed3b49dee5856116892d8c394 Mon Sep 17 00:00:00 2001 From: StevanFreeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:35:57 -0600 Subject: [PATCH 23/23] chore: update build script and build workflow --- .github/workflows/build_publish.yml | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_publish.yml b/.github/workflows/build_publish.yml index 1a32349..e4157bd 100644 --- a/.github/workflows/build_publish.yml +++ b/.github/workflows/build_publish.yml @@ -52,6 +52,10 @@ jobs: TEST_SURVEY_ID: ${{ vars.TEST_SURVEY_ID }} TEST_SURVEY_RECORD_ID: ${{ vars.TEST_SURVEY_RECORD_ID }} TEST_TEXT_FIELD: ${{ vars.TEST_TEXT_FIELD }} + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} - name: Upload build artifact uses: actions/upload-artifact@v3.1.2 with: diff --git a/package.json b/package.json index 5f85799..4bd3d28 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "lint-fix": "eslint --fix --ignore-path .eslintignore --ext .js,.ts . --max-warnings=0", "format-staged": "pretty-quick --staged", "format": "pretty-quick", - "build": "npm run tests && npm run clean && tsc --project tsconfig.cjs.json && tsc --project tsconfig.esm.json && node ./scripts/create_dist_package_json.js", + "build": "npm run test-coverage:ci && npm run clean && tsc --project tsconfig.cjs.json && tsc --project tsconfig.esm.json && node ./scripts/create_dist_package_json.js", "test:unit": "mocha -r ts-node/register", "test:integration": "mocha -r ts-node/register -r integrationTests/mochaRootHooks.ts", "tests:unit": "mocha -R progress -r ts-node/register ./tests/**/*.spec.ts",