diff --git a/docs/getting-started/number-lookup/lookup-a-number/README.md b/docs/getting-started/number-lookup/lookup-a-number/README.md index e0e0172c..c5f56189 100644 --- a/docs/getting-started/number-lookup/lookup-a-number/README.md +++ b/docs/getting-started/number-lookup/lookup-a-number/README.md @@ -1,4 +1,4 @@ -# Sinch Getting started: Lookup a number +# Sinch Getting started: Lookup a number (Node.js) This code is related to [Look up a number with the Node.js SDK](https://developers.sinch.com/docs/number-lookup-api-v2/getting-started/node/lookup-number#create-your-file). diff --git a/docs/snippets/conversation/messages/listLastMessagesByChannelIdentity.js b/docs/snippets/conversation/messages/listLastMessagesByChannelIdentity.js new file mode 100644 index 00000000..cb6353ce --- /dev/null +++ b/docs/snippets/conversation/messages/listLastMessagesByChannelIdentity.js @@ -0,0 +1,41 @@ +/** + * Sinch Node.js Snippet + * See: https://github.com/sinch/sinch-sdk-node/docs/snippets + */ +import { SinchClient } from '@sinch/sdk-core'; +import * as dotenv from 'dotenv'; +dotenv.config(); + +async function main() { + const projectId = process.env.SINCH_PROJECT_ID ?? 'MY_PROJECT_ID'; + const keyId = process.env.SINCH_KEY_ID ?? 'MY_KEY_ID'; + const keySecret = process.env.SINCH_KEY_SECRET ?? 'MY_KEY_SECRET'; + const conversationRegion = process.env.SINCH_CONVERSATION_REGION ?? 'MY_CONVERSATION_REGION'; + + // Channel identities to fetch the last message (can be phone numbers, social media IDs, etc. depending on the channel) + const channelIdentities = ['CHANNEL_IDENTITY_1', 'CHANNEL_IDENTITY_2']; + + const sinch = new SinchClient({ projectId, keyId, keySecret, conversationRegion }); + + try { + const response = await sinch.conversation.messages.listLastMessagesByChannelIdentity({ + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: channelIdentities, + messages_source: 'DISPATCH_SOURCE', + }, + }); + if (response.data.length === 0) { + console.log('No Messages found for the specified identities.'); + return; + } + console.log(`✅ Found ${response.data.length} Messages.`); + response.data.forEach((message) => { + console.log(message); + }); + } catch (err) { + console.error('❌ Failed to list the Messages for the specified identities:'); + console.error(err); + } +} + +main(); diff --git a/docs/snippets/package.json b/docs/snippets/package.json index b0dc9243..5ac0c1a9 100644 --- a/docs/snippets/package.json +++ b/docs/snippets/package.json @@ -42,6 +42,7 @@ "conversation:messages:send": "node conversation/messages/send.js", "conversation:messages:get": "node conversation/messages/get.js", "conversation:messages:list": "node conversation/messages/list.js", + "conversation:messages:listLastMessagesByChannelIdentity": "node conversation/messages/listLastMessagesByChannelIdentity.js", "conversation:messages:update": "node conversation/messages/update.js", "conversation:messages:delete": "node conversation/messages/delete.js", "conversation:templates:v1:create": "node conversation/templates/v1/create.js", diff --git a/examples/simple-examples/package.json b/examples/simple-examples/package.json index 1a8f64c3..c978813d 100644 --- a/examples/simple-examples/package.json +++ b/examples/simple-examples/package.json @@ -33,6 +33,7 @@ "conversation:messages:sendTextMessage": "ts-node src/conversation/messages/sendTextMessage.ts", "conversation:messages:get": "ts-node src/conversation/messages/get.ts", "conversation:messages:list": "ts-node src/conversation/messages/list.ts", + "conversation:messages:listLastMessagesByIdentities": "ts-node src/conversation/messages/listLastMessagesByIdentities.ts", "conversation:messages:update": "ts-node src/conversation/messages/update.ts", "conversation:messages:delete": "ts-node src/conversation/messages/delete.ts", "conversation:conversation:create": "ts-node src/conversation/conversation/create.ts", diff --git a/examples/simple-examples/src/conversation/messages/listLastMessagesByIdentities.ts b/examples/simple-examples/src/conversation/messages/listLastMessagesByIdentities.ts new file mode 100644 index 00000000..f1a26384 --- /dev/null +++ b/examples/simple-examples/src/conversation/messages/listLastMessagesByIdentities.ts @@ -0,0 +1,77 @@ +import { Conversation, PageResult } from '@sinch/sdk-core'; +import { + getAppIdFromConfig, + getContactIdFromConfig, getConversationIdFromConfig, getPhoneNumberFromConfig, + getPrintFormat, + initConversationService, + printFullResponse, +} from '../../config'; + +const populateMessagesList = ( + conversationPage: PageResult, + conversationList: Conversation.ConversationMessage[], + conversationDetailsList: string[], +) => { + conversationPage.data.map((message: Conversation.ConversationMessage) => { + conversationList.push(message); + conversationDetailsList.push(`${message.id} - ${message.accept_time}`); + }); +}; + +(async () => { + console.log('******************************************'); + console.log('* Messages_ListMessagesByChannelIdentity *'); + console.log('******************************************'); + + const phoneNumber = getPhoneNumberFromConfig().substring(1); + + const requestData: Conversation.ListLastMessagesByChannelIdentityRequestData = { + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: [phoneNumber], + messages_source: 'DISPATCH_SOURCE', + }, + }; + + const conversationService = initConversationService(); + + // ---------------------------------------------- + // Method 1: Fetch the data page by page manually + // ---------------------------------------------- + let response = await conversationService.messages.listLastMessagesByChannelIdentity(requestData); + + const messageList: Conversation.ConversationMessage[] = []; + const messagesDetailsList: string[] = []; + + // Loop on all the pages to get all the active numbers + let reachedEndOfPages = false; + while (!reachedEndOfPages) { + populateMessagesList(response, messageList, messagesDetailsList); + if (response.hasNextPage) { + response = await response.nextPage(); + } else { + reachedEndOfPages = true; + } + } + + const printFormat = getPrintFormat(process.argv); + + if (printFormat === 'pretty') { + console.log(messagesDetailsList.length > 0 + ? 'List of messages:\n' + messagesDetailsList.join('\n') + : 'Sorry, no messages were found.'); + } else { + printFullResponse(messageList); + } + + // --------------------------------------------------------------------- + // Method 2: Use the iterator and fetch data on more pages automatically + // --------------------------------------------------------------------- + for await (const message of conversationService.messages.listLastMessagesByChannelIdentity(requestData)) { + if (printFormat === 'pretty') { + console.log(`${message.id} - ${message.accept_time}`); + } else { + console.log(message); + } + } + +})(); diff --git a/packages/conversation/src/models/v1/enums.ts b/packages/conversation/src/models/v1/enums.ts index 1e8ce77e..b6d7628e 100644 --- a/packages/conversation/src/models/v1/enums.ts +++ b/packages/conversation/src/models/v1/enums.ts @@ -14,7 +14,10 @@ export type ConversationMetadataUpdateStrategy = 'REPLACE' | 'MERGE_PATCH' | str */ export type CardHeight = 'UNSPECIFIED_HEIGHT' | 'SHORT' | 'MEDIUM' | 'TALL' | string; -export type ConversationDirection = 'UNDEFINED_DIRECTION' | 'TO_APP' | 'TO_CONTACT' | string; +/** + * The direction of the message flow, indicating whether the message was sent to or from the Conversation API app. + */ +export type ConversationDirection = 'TO_APP' | 'TO_CONTACT' | string; export type ConversationMergeStrategy = 'MERGE' | string; diff --git a/packages/conversation/src/models/v1/index.ts b/packages/conversation/src/models/v1/index.ts index 0cb2b4fa..498305e9 100644 --- a/packages/conversation/src/models/v1/index.ts +++ b/packages/conversation/src/models/v1/index.ts @@ -68,6 +68,7 @@ export * from './kakaotalk-image'; export * from './kakaotalk-message'; export * from './kakaotalk-pricing'; export * from './list-apps-response'; +export * from './list-last-messages-by-channel-identity-request'; export * from './list-message'; export * from './list-section'; export * from './list-webhooks-response'; diff --git a/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/index.ts b/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/index.ts new file mode 100644 index 00000000..7e489c5a --- /dev/null +++ b/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/index.ts @@ -0,0 +1 @@ +export type { ListLastMessagesByChannelIdentityRequest } from './list-last-messages-by-channel-identity-request'; diff --git a/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/list-last-messages-by-channel-identity-request.ts b/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/list-last-messages-by-channel-identity-request.ts new file mode 100644 index 00000000..84782d91 --- /dev/null +++ b/packages/conversation/src/models/v1/list-last-messages-by-channel-identity-request/list-last-messages-by-channel-identity-request.ts @@ -0,0 +1,30 @@ +import { ConversationChannel } from '../conversation-channel'; +import { ConversationDirection, ConversationMessagesView, MessageSource } from '../enums'; + +/** + * Request body for listing messages by channel identity. NOTE: You can use either contact_ids OR channel_identities, but not both in the same request. + */ +export interface ListLastMessagesByChannelIdentityRequest { + /** Optional. Filter messages by `channel_identity`. */ + channel_identities?: string[]; + /** Optional. Resource name (id) of the contact. In case the messages source is set to `CONVERSATION_SOURCE`: Can list last messages by contact_id. In case the messages source is set to `DISPATCH_SOURCE`: The field is unsupported and cannot be set. */ + contact_ids?: string[]; + /** Optional. Resource name (id) of the app. */ + app_id?: string; + /** Optional. Specifies the message source for which the request will be processed. Default is `DISPATCH_SOURCE`. */ + messages_source?: MessageSource; + /** Optional. Maximum number of messages to fetch. Defaults to 10 and the maximum is 1000. */ + page_size?: number; + /** Optional. Next page token previously returned if any. */ + page_token?: string; + /** Optional. Specifies the representation in which messages should be returned. Default to `WITH_METADATA`. */ + view?: ConversationMessagesView; + /** Optional. Only fetch messages with `accept_time` after this date. */ + start_time?: Date; + /** Optional. Only fetch messages with `accept_time` before this date. */ + end_time?: Date; + /** Optional. Only fetch messages from the `channel`. */ + channel?: ConversationChannel; + /** Optional. Only fetch messages with the specified `direction`. If direction is not specified, it will list both TO_APP and TO_CONTACT messages. */ + direction?: ConversationDirection; +} diff --git a/packages/conversation/src/models/v1/requests/messages/messages-request-data.ts b/packages/conversation/src/models/v1/requests/messages/messages-request-data.ts index a6d751e6..63e28abc 100644 --- a/packages/conversation/src/models/v1/requests/messages/messages-request-data.ts +++ b/packages/conversation/src/models/v1/requests/messages/messages-request-data.ts @@ -1,4 +1,4 @@ -import { ConversationMessagesView, MessageSource } from '../../enums'; +import { ConversationDirection, ConversationMessagesView, MessageSource } from '../../enums'; import { ConversationChannel } from '../../conversation-channel'; import { Recipient } from '../../recipient'; import { @@ -9,9 +9,12 @@ import { SendListMessageRequest, SendLocationMessageRequest, SendMediaMessageRequest, - SendMessageRequest, SendTemplateMessageRequest, SendTextMessageRequest, + SendMessageRequest, + SendTemplateMessageRequest, + SendTextMessageRequest, } from '../../send-message-request'; import { UpdateMessageRequest } from '../../update-message-request'; +import { ListLastMessagesByChannelIdentityRequest } from '../../list-last-messages-by-channel-identity-request'; export interface DeleteMessageRequestData { /** The unique ID of the message. */ @@ -50,6 +53,12 @@ export interface ListMessagesRequestData { 'only_recipient_originated'?: boolean; /** Only fetch messages from the `channel`. */ 'channel'?: ConversationChannel; + /** Optional. Only fetch messages with the specified `direction`. If direction is not specified, it will list both TO_APP and TO_CONTACT messages. */ + 'direction'?: ConversationDirection; +} +export interface ListLastMessagesByChannelIdentityRequestData { + /** Request body for listing messages by channel identity. NOTE: You can use either contact_ids OR channel_identities, but not both in the same request. */ + 'listLastMessagesByChannelIdentityRequestBody': ListLastMessagesByChannelIdentityRequest; } export interface SendMessageRequestData { /** This is the request body for sending a message. `app_id`, `recipient`, and `message` are all required fields. */ diff --git a/packages/conversation/src/rest/v1/conversation/conversation-api.ts b/packages/conversation/src/rest/v1/conversation/conversation-api.ts index 46be2687..a75f6ca3 100644 --- a/packages/conversation/src/rest/v1/conversation/conversation-api.ts +++ b/packages/conversation/src/rest/v1/conversation/conversation-api.ts @@ -26,7 +26,7 @@ import { LazyConversationApiClient } from '../conversation-service'; export class ConversationApi extends ConversationDomainApi { constructor(lazyApiClient: LazyConversationApiClient) { - super(lazyApiClient, 'AppApi'); + super(lazyApiClient, 'ConversationApi'); } /** diff --git a/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts index d1d2c579..eace00bc 100644 --- a/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts +++ b/packages/conversation/src/rest/v1/messages/messages-api.jest.fixture.ts @@ -6,6 +6,7 @@ import { SendMessageResponse, DeleteMessageRequestData, GetMessageRequestData, + ListLastMessagesByChannelIdentityRequestData, ListMessagesRequestData, UpdateMessageRequestData, SendCardMessageRequestData, @@ -34,6 +35,13 @@ export class MessagesApiFixture implements Partial> { * Fixture associated to function list */ public list: jest.Mock, [ListMessagesRequestData]> = jest.fn(); + /** + * Fixture associated to function listLastMessagesByChannelIdentity + */ + public listLastMessagesByChannelIdentity: jest.Mock< + ApiListPromise, + [ListLastMessagesByChannelIdentityRequestData] + > = jest.fn(); /** * Fixture associated to function sendCardMessage */ diff --git a/packages/conversation/src/rest/v1/messages/messages-api.ts b/packages/conversation/src/rest/v1/messages/messages-api.ts index b68075cf..3ff9c6d4 100644 --- a/packages/conversation/src/rest/v1/messages/messages-api.ts +++ b/packages/conversation/src/rest/v1/messages/messages-api.ts @@ -10,6 +10,7 @@ import { ConversationMessage, DeleteMessageRequestData, GetMessageRequestData, + ListLastMessagesByChannelIdentityRequestData, ListMessagesRequestData, Recipient, SendCardMessageRequestData, @@ -97,7 +98,6 @@ export class MessagesApi extends ConversationDomainApi { * @return {ApiListPromise} */ public list(data: ListMessagesRequestData): ApiListPromise { - data['messages_source'] = data['messages_source'] !== undefined ? data['messages_source'] : 'CONVERSATION_SOURCE'; const getParams = this.client.extractQueryParams(data, [ 'conversation_id', 'contact_id', @@ -111,6 +111,7 @@ export class MessagesApi extends ConversationDomainApi { 'messages_source', 'only_recipient_originated', 'channel', + 'direction', ]); const headers: { [key: string]: string | undefined } = { 'Content-Type': 'application/json', @@ -145,6 +146,50 @@ export class MessagesApi extends ConversationDomainApi { return listPromise as ApiListPromise; } + /** + * List messages by channel identity + * Retrieves the last message sent to specified channel identities. In CONVERSATION_SOURCE mode, you can query either by channel_identities or by contact_ids. Note: Use either contact_ids OR channel_identities per request, not both. DISPATCH_SOURCE mode does not support contact_ids. + * @param { ListLastMessagesByChannelIdentityRequestData } data - The data to provide to the API call. + */ + public listLastMessagesByChannelIdentity( + data: ListLastMessagesByChannelIdentityRequestData, + ): ApiListPromise { + const getParams = this.client.extractQueryParams(data, [] as never[]); + const headers: { [key: string]: string | undefined } = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }; + + const body: RequestBody = data['listLastMessagesByChannelIdentityRequestBody'] + ? JSON.stringify(data['listLastMessagesByChannelIdentityRequestBody']) : '{}'; + const basePathUrl = `${this.client.apiClientOptions.hostname}/v1/projects/${this.client.apiClientOptions.projectId}/messages:fetch-last-message`; + + const requestOptionsPromise + = this.client.prepareOptions(basePathUrl, 'POST', getParams, headers, body || undefined); + + const operationProperties: PaginatedApiProperties = { + pagination: PaginationEnum.TOKEN2, + apiName: this.apiName, + operationId: 'ListMessagesByChannelIdentity', + dataKey: 'messages', + }; + + // Create the promise containing the response wrapped as a PageResult + const listPromise = buildPageResultPromise( + this.client, + requestOptionsPromise, + operationProperties); + + // Add properties to the Promise to offer the possibility to use it as an iterator + Object.assign( + listPromise, + createIteratorMethodsForPagination( + this.client, requestOptionsPromise, listPromise, operationProperties), + ); + + return listPromise as ApiListPromise; + } + /** * Send a message * You can send a message from a Conversation app to a contact associated with that app. If the recipient is not associated with an existing contact, a new contact will be created. The message is added to the active conversation with the contact if a conversation already exists. If no active conversation exists a new one is started automatically. You can find all of your IDs and authentication credentials on the [Sinch Customer Dashboard](https://dashboard.sinch.com/convapi/overview). diff --git a/packages/conversation/tests/rest/v1/messages/messages-api.test.ts b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts index 513b67ce..e6eed3bc 100644 --- a/packages/conversation/tests/rest/v1/messages/messages-api.test.ts +++ b/packages/conversation/tests/rest/v1/messages/messages-api.test.ts @@ -407,6 +407,65 @@ describe('MessagesApi', () => { }); }); + describe ('listLastMessagesByChannelIdentity', () => { + it('should make a POST request to list the last messages related to the channel identities', async () => { + // Given + const requestData: Conversation.ListLastMessagesByChannelIdentityRequestData = { + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: [ + '4712345678', + ], + messages_source: 'DISPATCH_SOURCE', + direction: 'TO_CONTACT', + }, + }; + const mockData: Conversation.ConversationMessage[] = [ + { + id: 'id', + direction: 'TO_CONTACT', + app_message: { + explicit_channel_message: {}, + text_message: { + text: 'Hello from Sinch - RCS', + }, + agent: null, + explicit_channel_omni_message: {}, + channel_specific_message: {}, + }, + channel_identity: { + channel: 'RCS', + identity: '4712345678', + app_id: '', + }, + conversation_id: '', + contact_id: '', + metadata: '', + accept_time: new Date('2019-08-24T14:15:22Z'), + sender_id: '', + processing_mode: 'DISPATCH', + injected: false, + message_status: null, + }, + ]; + const expectedResponse = { + data: mockData, + hasNextPage: false, + nextPageValue: '', + nextPage: jest.fn(), + }; + + // When + fixture.listLastMessagesByChannelIdentity.mockResolvedValue(expectedResponse); + messagesApi.listLastMessagesByChannelIdentity = fixture.listLastMessagesByChannelIdentity; + const response = await messagesApi.listLastMessagesByChannelIdentity(requestData); + + // Then + expect(response).toEqual(expectedResponse); + expect(response.data).toBeDefined(); + expect(fixture.listLastMessagesByChannelIdentity).toHaveBeenCalledWith(requestData); + }); + }); + describe ('sendMessage', () => { // Given const sendMessageRequest: Omit, 'recipient'> = { diff --git a/packages/conversation/tests/rest/v1/messages/messages.steps.ts b/packages/conversation/tests/rest/v1/messages/messages.steps.ts index 5f704c8b..e3433198 100644 --- a/packages/conversation/tests/rest/v1/messages/messages.steps.ts +++ b/packages/conversation/tests/rest/v1/messages/messages.steps.ts @@ -81,8 +81,8 @@ When('I iterate manually over the messages pages', async () => { }); Then('the messages list contains {string} messages', (expectedAnswer: string) => { - const expectedServices = parseInt(expectedAnswer, 10); - assert.equal(messagesList.length, expectedServices); + const expectedMessagesCount = parseInt(expectedAnswer, 10); + assert.equal(messagesList.length, expectedMessagesCount); }); Then('the result contains the data from {string} pages', (expectedAnswer: string) => { @@ -138,30 +138,64 @@ Then('the delete message response contains no data', () => { }); When('I send a request to list the last messages sent to specified channel identities', async () => { - // TODO + listResponse = await messagesApi.listLastMessagesByChannelIdentity({ + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: ['12015555555', '12017777777', '7504610123456789'], + messages_source: 'CONVERSATION_SOURCE', + page_size: 2, + }, + }); }); Then('the response contains {string} last messages sent to specified channel identities', (expectedAnswer: string) => { - // TODO - assert.equal(expectedAnswer, expectedAnswer); + const expectedMessagesCount = parseInt(expectedAnswer, 10); + assert.equal(listResponse.data.length, expectedMessagesCount); }); When('I send a request to list all the last messages sent to specified channel identities', async () => { - // TODO + messagesList = []; + for await (const message of messagesApi.listLastMessagesByChannelIdentity({ + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: ['12015555555', '12017777777', '7504610123456789'], + messages_source: 'CONVERSATION_SOURCE', + page_size: 2, + }, + })) { + messagesList.push(message); + } }); When('I iterate manually over the last messages sent to specified channel identities pages', async () => { - // TODO + messagesList = []; + listResponse = await messagesApi.listLastMessagesByChannelIdentity({ + listLastMessagesByChannelIdentityRequestBody: { + channel_identities: ['12015555555', '12017777777', '7504610123456789'], + messages_source: 'CONVERSATION_SOURCE', + page_size: 2, + }, + }); + messagesList.push(...listResponse.data); + pagesIteration = 1; + let reachedEndOfPages = false; + while (!reachedEndOfPages) { + if (listResponse.hasNextPage) { + listResponse = await listResponse.nextPage(); + messagesList.push(...listResponse.data); + pagesIteration++; + } else { + reachedEndOfPages = true; + } + } }); // eslint-disable-next-line max-len Then('the response list contains {string} last messages sent to specified channel identities', (expectedAnswer: string) => { - // TODO - assert.equal(expectedAnswer, expectedAnswer); + const expectedMessagesCount = parseInt(expectedAnswer, 10); + assert.equal(messagesList.length, expectedMessagesCount); }); // eslint-disable-next-line max-len Then('the result contains the data from {string} pages of last messages sent to specified channel identities', (expectedAnswer: string) => { - // TODO - assert.equal(expectedAnswer, expectedAnswer); + const expectedPagesCount = parseInt(expectedAnswer, 10); + assert.equal(pagesIteration, expectedPagesCount); }); diff --git a/packages/sdk-client/src/client/api-client-pagination-helper.ts b/packages/sdk-client/src/client/api-client-pagination-helper.ts index f6b396af..d5f833f6 100644 --- a/packages/sdk-client/src/client/api-client-pagination-helper.ts +++ b/packages/sdk-client/src/client/api-client-pagination-helper.ts @@ -64,6 +64,10 @@ class SinchIterator implements AsyncIterator { const newParams = { page_token: pageResult.nextPageValue, }; + if (requestOptions.method === 'POST') { + return updateBodyParamsAndSendRequest( + this.apiClient, newParams, requestOptions, this.paginatedOperationProperties); + } return updateQueryParamsAndSendRequest( this.apiClient, newParams, requestOptions, this.paginatedOperationProperties); } @@ -112,6 +116,34 @@ const updateQueryParamsAndSendRequest = ( }); }; +const updateBodyParamsAndSendRequest = ( + apiClient: ApiClient, + newParams: { [key: string]: string }, + requestOptions: RequestOptions, + paginatedApiProperties: PaginatedApiProperties, +): Promise> => { + requestOptions.body = JSON.stringify({ + ...JSON.parse(requestOptions.body as string), + ...sanitizeNewParams(newParams), + }); + return apiClient.processCallWithPagination({ + url: requestOptions.hostname, + requestOptions, + ...paginatedApiProperties, + }); +}; + +const sanitizeNewParams = (newParams: { [key: string]: string }): { [key: string]: string } => { + const sanitizedParams: { [key: string]: string } = {}; + for (const key in newParams) { + if (newParams[key]) { + // Remove the quotes added by JSON.stringify to the value of the new params to avoid having pageToken: ""abc"" instead of pageToken: "abc" in the request body + sanitizedParams[key] = JSON.parse(newParams[key]); + } + } + return sanitizedParams; +}; + export const createIteratorMethodsForPagination = ( apiClient: ApiClient, requestOptionsPromise: Promise, @@ -160,7 +192,9 @@ export const createNextPageMethod = ( throw new Error(`Error: the pagination method (${context.pagination}) is not supported`); } - const pageResultPromise = updateQueryParamsAndSendRequest(apiClient, newParams, requestOptions, context); + const pageResultPromise = requestOptions.method === 'POST' + ? updateBodyParamsAndSendRequest(apiClient, newParams, requestOptions, context) + : updateQueryParamsAndSendRequest(apiClient, newParams, requestOptions, context); const requestOptionsPromise = new Promise((resolve) => { resolve(requestOptions);