diff --git a/README.md b/README.md index e9398ff..14c6ca3 100644 --- a/README.md +++ b/README.md @@ -222,3 +222,75 @@ logger.error('error message', { error: new Error('error') }); ``` + +## Monday API Client + +
+Querying the monday.com GraphQL API seamlessly on behalf of the connected user, or using a provided API token. + +#### initialize + +```typescript +import { MondayApiClient } from '@mondaycom/apps-sdk'; + +const mondayClient = new MondayApiClient(); +mondayClient.setToken(token); +mondayClient.setApiVersion('2023-10'); +``` + +```typescript +import { MondayApiClient } from '@mondaycom/apps-sdk'; + +const mondayClient = new MondayApiClient(token); +mondayClient.setApiVersion('2023-10'); +``` + +#### API + +```typescript +const query = `query { + items(ids: [1234]) { + column_values(ids: ["text1"]) { + text + } + } + }`; + +const response = await mondayClient.api(query); +``` + +```typescript +const query = `query ($item_id: ID!, $column_id: String!){ + items(ids: [$item_id]) { + column_values(ids: [$column_id]) { + text + } + } + }`; +const variables = { + item_id: 1234, + $column_id: 'text1', +}; +const response = await mondayClient.api(query, { variables }); +``` + +```typescript +const query = `mutation ($value: String, $board_id: ID!, $item_id: ID, $column_id: String!){ + change_simple_column_value ( + board_id: $board_id, + item_id: $item_id, + column_id: $column_id, + value: $value ) { + id + } + }`; +const variables = { + board_id: 12345, + item_id: 423432, + column_id: 'status', + value: 'new value...', +}; +const response = await await mondayClient.api(query, { variables }); +``` + +
diff --git a/lib/index.ts b/lib/index.ts index 50c8af8..128e3de 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,5 +1,6 @@ import { EnvironmentVariablesManager } from 'lib/environment-variables-manager'; import { Logger } from 'lib/logger'; +import { MondayApiClient } from 'lib/monday-api-client'; import { Queue } from 'lib/queue'; import { SecureStorage } from 'lib/secure-storage'; import { Period, Storage } from 'lib/storage'; @@ -10,5 +11,6 @@ export { Period, EnvironmentVariablesManager, Logger, - Queue + Queue, + MondayApiClient }; diff --git a/lib/minimal-package.ts b/lib/minimal-package.ts index 6559317..ef8c2c5 100644 --- a/lib/minimal-package.ts +++ b/lib/minimal-package.ts @@ -1 +1 @@ -export default { name: '@mondaycom/apps-sdk', version: '2.2.0' }; +export default { name: '@mondaycom/apps-sdk', version: '2.3.0' }; diff --git a/lib/monday-api-client/index.ts b/lib/monday-api-client/index.ts new file mode 100644 index 0000000..d2f1083 --- /dev/null +++ b/lib/monday-api-client/index.ts @@ -0,0 +1,4 @@ +import { MondayApiClient } from './monday-api-client' +export { + MondayApiClient +}; diff --git a/lib/monday-api-client/monday-api-client.ts b/lib/monday-api-client/monday-api-client.ts new file mode 100644 index 0000000..acce6b4 --- /dev/null +++ b/lib/monday-api-client/monday-api-client.ts @@ -0,0 +1,78 @@ +import {BadRequestError, InternalServerError} from 'errors/apps-sdk-error'; +import {Token} from 'types/general'; +import {isDefined} from 'types/guards'; +import { + APIData, + APIFetchResponse, + APIOptions, + APIResponse, + APIVersion, + IMondayApiClient +} from 'types/monday-api-client'; +import {fetchWrapper} from 'utils/fetch-wrapper'; +import { Logger } from 'utils/logger'; +const logger = new Logger('MondayApiClient', { mondayInternal: true }); +const API_URL = 'https://api.monday.com/v2/'; +export class MondayApiClient implements IMondayApiClient { + private token?: Token; + + private apiVersion?: APIVersion; + + constructor(token?: Token) { + this.token = token; + } + + setToken(token: Token) { + this.token = token; + } + + setApiVersion(version: APIVersion){ + this.apiVersion = version + } + + async api(query: string, options: APIOptions = {}) { + if (!this.token) { + logger.warn('[mondayApiClientFetch] Error Token is missing'); + throw new BadRequestError('Token is missing'); + } + + const params: APIData = { query, variables: options.variables }; + const apiVersion = options.apiVersion || this.apiVersion; + + const fetchObj = { + headers: { + 'Content-Type': 'application/json', + ...(this.token && { 'Authorization': this.token }), + ...(apiVersion && { 'API-Version': apiVersion }) + }, + method: 'POST', + body: params ? JSON.stringify(params || {}) : undefined + }; + + let result: APIFetchResponse | undefined; + try { + result = await fetchWrapper(API_URL, fetchObj); + } catch (error: unknown) { + logger.error('[mondayApiClientFetch] Unexpected error occurred while communicating with secure storage', { error: error as Error }); + throw new InternalServerError('An issue occurred while accessing secure storage'); + } + + + if (!isDefined(result)) { + throw new InternalServerError('some thing went wrong when communicating with mondayApiClientFetch'); + } + + if (isDefined(result.errors)) { + const errorMessage = result.errors.map(e=>e?.message).join(', '); + logger.error(`[mondayApiClientFetch] Errors occurred while communicating with secure storage.\nErrors: ${errorMessage}`); + throw new BadRequestError(errorMessage); + } + + if (!isDefined(result.data)) { + throw new InternalServerError('some thing went wrong when communicating with mondayApiClientFetch data filed returned empty'); + } + + const { data, account_id } = result; + return { data, account_id } + } +} diff --git a/lib/storage/base-storage.ts b/lib/storage/base-storage.ts index 5b6170d..734c187 100644 --- a/lib/storage/base-storage.ts +++ b/lib/storage/base-storage.ts @@ -1,7 +1,8 @@ import {BadRequestError, InternalServerError} from 'errors/apps-sdk-error'; import {RequestOptions} from 'types/fetch'; +import {Token} from 'types/general'; import {isDefined} from 'types/guards'; -import {Options, Token} from 'types/storage'; +import {Options} from 'types/storage'; import {fetchWrapper} from 'utils/fetch-wrapper'; import {Logger} from 'utils/logger'; diff --git a/lib/types/general.ts b/lib/types/general.ts index b53f125..1ca9547 100644 --- a/lib/types/general.ts +++ b/lib/types/general.ts @@ -1 +1,3 @@ export type JsonValue = string | number | boolean | null | Array | { [key: string]: JsonValue }; + +export type Token = string; diff --git a/lib/types/monday-api-client.ts b/lib/types/monday-api-client.ts new file mode 100644 index 0000000..a3dc3f7 --- /dev/null +++ b/lib/types/monday-api-client.ts @@ -0,0 +1,60 @@ + +export type APIOptions = { + /** + * Access token for the API + * If not set, will use the credentials of the current user (client only) + */ + token?: string; + + /** + * An object containing GraphQL query variables + */ + variables?: object; + + /** + * A string specifying which version of the API should be used + * If not set, will use the current API version + */ + apiVersion?: string; +} + +export type APIData = { + query: string; + variables?: object; +} + +export type APIVersion = string; + +export type APIResponse = { + data?: { + data: object + }, + account_id: number +} + +export type APIFetchResponse = { + errors?: Array<{ message: string }>, +} & APIResponse; + +export type IMondayApiClient = { + + /** + * Used for querying the monday.com GraphQL API seamlessly on behalf of the connected user, or using a provided API token. + * For more information about the GraphQL API and all queries and mutations possible, read the [API Documentation](https://monday.com/developers/v2) + * @param query A [GraphQL](https://graphql.org/) query, can be either a query (retrieval operation) or a mutation (creation/update/deletion operation). + * Placeholders may be used, which will be substituted by the variables object passed within the options. + * @param options + */ + api: (query: string, options: APIOptions) => Promise, + /** + * Instead of passing the API token to the `api()` method on each request, you can set the API token once using: + * @param token Access token for the API + */ + setToken(token: string): void; + + /** + * Allows to set the API version for future requests. + * @param version A string specifying which version of the API should be used + */ + setApiVersion(version: string): void; +} diff --git a/lib/types/storage.ts b/lib/types/storage.ts index 92efab8..df5b746 100644 --- a/lib/types/storage.ts +++ b/lib/types/storage.ts @@ -1,4 +1,4 @@ -export type Token = string; + export enum Period { DAILY='DAILY', MONTHLY='MONTHLY', diff --git a/package.json b/package.json index 50cca3a..d614c1b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mondaycom/apps-sdk", - "version": "2.2.0", + "version": "2.3.0", "description": "monday apps SDK for NodeJS", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js",