@kontent-ai/delivery-sdk
Version:
Official Kontent.AI Delivery API SDK
337 lines (300 loc) • 13.1 kB
text/typescript
import { IHttpService } from '@kontent-ai/core-sdk';
import { IDeliveryClientConfig } from '../config';
import { Contracts } from '../contracts';
import {
Responses,
IContentItem,
IContentTypeQueryConfig,
IGroupedNetworkResponse,
IItemQueryConfig,
IDeliveryNetworkResponse,
ILanguagesQueryConfig,
ITaxonomyQueryConfig,
ISyncInitQueryConfig,
ClientTypes
} from '../models';
import {
IKontentListAllResponse,
IKontentListResponse,
IListAllQueryConfig,
ISDKInfo
} from '../models/common/common-models';
import { BaseDeliveryQueryService } from './base-delivery-query.service';
import { IMappingService } from './mapping.service';
export class QueryService<TClientTypes extends ClientTypes> extends BaseDeliveryQueryService<TClientTypes> {
constructor(
config: IDeliveryClientConfig,
httpService: IHttpService<any>,
sdkInfo: ISDKInfo,
mappingService: IMappingService<TClientTypes>
) {
super(config, httpService, sdkInfo, mappingService);
}
/**
* Gets single item from given url
* @param url Url used to get single item
* @param queryConfig Query configuration
*/
async getSingleItemAsync<TContentItem extends IContentItem = TClientTypes['contentItemType']>(
url: string,
queryConfig: IItemQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IViewContentItemResponse<TContentItem, TClientTypes['contentItemType']>,
Contracts.IViewContentItemContract
>
> {
const response = await this.getResponseAsync<Contracts.IViewContentItemContract>(url, queryConfig);
return this.mapNetworkResponse<
Responses.IViewContentItemResponse<TContentItem, TClientTypes['contentItemType']>,
Contracts.IViewContentItemContract
>(this.mappingService.viewContentItemResponse<TContentItem>(response.data), response);
}
/**
* Gets single feed response. Might not contain all items in your environment.
* @param url Url
* @param queryConfig Query configuration
*/
async getItemsFeed<TContentItem extends IContentItem = TClientTypes['contentItemType']>(
url: string,
queryConfig: IItemQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IListItemsFeedResponse<TContentItem, TClientTypes['contentItemType']>,
Contracts.IItemsFeedContract
>
> {
const response = await this.getResponseAsync<Contracts.IItemsFeedContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.itemsFeedResponse<TContentItem>(response.data), response);
}
/**
* Gets single used in response. Might not contain all used in references.
* @param url Url
* @param queryConfig Query configuration
*/
async getUsedIn(
url: string,
queryConfig: IItemQueryConfig
): Promise<IDeliveryNetworkResponse<Responses.IUsedInResponse<TClientTypes>, Contracts.IUsedInItemsContract>> {
const response = await this.getResponseAsync<Contracts.IUsedInItemsContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.usedInResponse(response.data), response);
}
/**
* Gets multiple items from given url
* @param url Url used to get multiple items
* @param queryConfig Query configuration
*/
async getMultipleItems<TContentItem extends IContentItem = TClientTypes['contentItemType']>(
url: string,
queryConfig: IItemQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IListContentItemsResponse<TContentItem, TClientTypes['contentItemType']>,
Contracts.IListContentItemsContract
>
> {
const response = await this.getResponseAsync<Contracts.IListContentItemsContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.listContentItemsResponse(response.data), response);
}
/**
* Gets single content type from given url
* @param url Url used to get single type
* @param queryConfig Query configuration
*/
async getSingleType(
url: string,
queryConfig: IContentTypeQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IViewContentTypeResponse<TClientTypes['contentTypeCodenames']>,
Contracts.IViewContentTypeContract
>
> {
const response = await this.getResponseAsync<Contracts.IViewContentTypeContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.viewContentTypeResponse(response.data), response);
}
/**
* Gets multiple content types from given url
* @param url Url used to get multiple types
* @param queryConfig Query configuration
*/
async getMultipleTypes(
url: string,
queryConfig: IContentTypeQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IListContentTypesResponse<TClientTypes['contentTypeCodenames']>,
Contracts.IListContentTypeContract
>
> {
const response = await this.getResponseAsync<Contracts.IListContentTypeContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.listContentTypesResponse(response.data), response);
}
/**
* Initializes synchronization of changes in content items based on the specified parameters. After the initialization,
* you'll get an X-Continuation token in the response.
* Use the token to synchronize changes in the content items matching the initialization criteria.
* @param url Url
* @param queryConfig Query configuration
*/
async initializeSync(
url: string,
queryConfig: ISyncInitQueryConfig
): Promise<IDeliveryNetworkResponse<Responses.IInitializeSyncResponse, Contracts.IInitializeSyncContract>> {
const response = await this.postResponseAsync<Contracts.IInitializeSyncContract>(url, {}, queryConfig);
return this.mapNetworkResponse(this.mappingService.initializeContentSync(response.data), response);
}
/**
* Retrieve a list of delta updates to recently changed content items in the specified environment.
* The types of items you get is determined by the X-Continuation token you use.
* @param url Url used to get multiple types
* @param queryConfig Query configuration
*/
async syncChanges(
url: string,
queryConfig: IContentTypeQueryConfig
): Promise<IDeliveryNetworkResponse<Responses.ISyncChangesResponse, Contracts.ISyncChangesContract>> {
const response = await this.getResponseAsync<Contracts.ISyncChangesContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.syncChanges(response.data), response);
}
/**
* Gets languages
* @param url Url
* @param queryConfig Query configuration
*/
async getLanguages(
url: string,
queryConfig: ILanguagesQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IListLanguagesResponse<TClientTypes['languageCodenames']>,
Contracts.IListLanguagesContract
>
> {
const response = await this.getResponseAsync<Contracts.IListLanguagesContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.listLanguagesResponse(response.data), response);
}
/**
* Gets single taxonomy from given url
* @param url Url used to get single taxonomy
* @param queryConfig Query configuration
*/
async getTaxonomy(
url: string,
queryConfig: ITaxonomyQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IViewTaxonomyResponse<TClientTypes['taxonomyCodenames']>,
Contracts.IViewTaxonomyGroupContract
>
> {
const response = await this.getResponseAsync<Contracts.IViewTaxonomyGroupContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.viewTaxonomyResponse(response.data), response);
}
/**
* Gets multiple taxonomies from given url
* @param url Url used to get multiple taxonomies
* @param queryConfig Query configuration
*/
async getTaxonomies(
url: string,
queryConfig: ITaxonomyQueryConfig
): Promise<
IDeliveryNetworkResponse<
Responses.IListTaxonomiesResponse<TClientTypes['taxonomyCodenames']>,
Contracts.IListTaxonomyGroupsContract
>
> {
const response = await this.getResponseAsync<Contracts.IListTaxonomyGroupsContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.listTaxonomiesResponse(response.data), response);
}
/**
* Gets single content type element from given url
* @param url Url used to get single content type element
* @param queryConfig Query configuration
*/
async getElementAsync(
url: string,
queryConfig: ITaxonomyQueryConfig
): Promise<
IDeliveryNetworkResponse<Responses.IViewContentTypeElementResponse, Contracts.IViewContentTypeElementContract>
> {
const response = await this.getResponseAsync<Contracts.IViewContentTypeElementContract>(url, queryConfig);
return this.mapNetworkResponse(this.mappingService.viewContentTypeElementResponse(response.data), response);
}
async getListAllResponse<
TResponse extends IKontentListResponse,
TAllResponse extends IKontentListAllResponse,
TContract
>(data: {
page: number;
getResponse: (
nextPageUrl?: string,
continuationToken?: string
) => Promise<IDeliveryNetworkResponse<TResponse, TContract>>;
allResponseFactory: (
items: any[],
responses: IDeliveryNetworkResponse<TResponse, TContract>[]
) => IGroupedNetworkResponse<TAllResponse>;
listQueryConfig?: IListAllQueryConfig<TResponse, TContract>;
}): Promise<IGroupedNetworkResponse<TAllResponse>> {
const responses = await this.getListAllResponseInternalAsync({
page: data.page,
resolvedResponses: [],
getResponse: data.getResponse,
nextPageUrl: undefined,
continuationToken: undefined,
listQueryConfig: data.listQueryConfig
});
return data.allResponseFactory(
responses.reduce((prev: any[], current) => {
prev.push(...current.data.items);
return prev;
}, []),
responses
);
}
private async getListAllResponseInternalAsync<TResponse extends IKontentListResponse, TContract>(data: {
page: number;
nextPageUrl?: string;
continuationToken?: string;
getResponse: (
nextPageUrl?: string,
continuationToken?: string
) => Promise<IDeliveryNetworkResponse<TResponse, TContract>>;
resolvedResponses: IDeliveryNetworkResponse<TResponse, TContract>[];
listQueryConfig?: IListAllQueryConfig<TResponse, TContract>;
}): Promise<IDeliveryNetworkResponse<TResponse, TContract>[]> {
if (data.listQueryConfig?.pages) {
if (data.page > data.listQueryConfig.pages) {
// page limit reached, return result
return data.resolvedResponses;
}
}
const response = await data.getResponse(data.nextPageUrl, data.continuationToken);
if (data.listQueryConfig?.delayBetweenRequests) {
await this.sleep(data.listQueryConfig.delayBetweenRequests);
}
data.resolvedResponses.push(response);
if (data.listQueryConfig?.responseFetched) {
data.listQueryConfig.responseFetched(response, data.nextPageUrl, data.continuationToken);
}
const nextPage = response.data.pagination?.nextPage;
const continuationToken = response.xContinuationToken;
if (nextPage || continuationToken) {
// recursively fetch next page data
return await this.getListAllResponseInternalAsync({
page: data.page + 1,
nextPageUrl: nextPage,
continuationToken: continuationToken,
listQueryConfig: data.listQueryConfig,
getResponse: data.getResponse,
resolvedResponses: data.resolvedResponses
});
}
return data.resolvedResponses;
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}