UNPKG

@mediarithmics/plugins-nodejs-sdk

Version:

This is the mediarithmics nodejs to help plugin developers bootstrapping their plugin without having to deal with most of the plugin boilerplate

125 lines (104 loc) 4.77 kB
import express from 'express'; import _ from 'lodash'; import { PluginProperty, PluginPropertyResponse } from '../../api/core/plugin/PluginPropertyInterface'; import { Catalog, CatalogResponse, RecommendationsWrapper } from '../../api/datamart'; import { RecommenderRequest } from '../../api/plugin/recommender/RecommenderRequestInterface'; import { BasePlugin, PropertiesWrapper } from '../common/BasePlugin'; export interface RecommenderBaseInstanceContext { properties: PropertiesWrapper; } export abstract class RecommenderPlugin extends BasePlugin<RecommenderBaseInstanceContext> { instanceContext: Promise<RecommenderBaseInstanceContext>; constructor() { super(); // We init the specific route to listen for activity analysis requests this.initRecommendationRequest(); this.setErrorHandler(); } // Helper to fetch the activity analyzer resource with caching async fetchRecommenderCatalogs(recommenderId: string): Promise<Catalog[]> { const recommenderCatalogsResponse = await super.requestGatewayHelper<CatalogResponse>( 'GET', `${this.outboundPlatformUrl}/v1/recommenders/${recommenderId}/catalogs`, ); this.logger.debug( `Fetched recommender catalogs: ${recommenderId} - ${JSON.stringify(recommenderCatalogsResponse.data)}`, ); return recommenderCatalogsResponse.data; } // Method to build an instance context // To be overriden to get a cutom behavior // Helper to fetch the activity analyzer resource with caching async fetchRecommenderProperties(recommenderId: string): Promise<PluginProperty[]> { const recommenderPropertyResponse = await super.requestGatewayHelper<PluginPropertyResponse>( 'GET', `${this.outboundPlatformUrl}/v1/recommenders/${recommenderId}/properties`, ); this.logger.debug( `Fetched recommender Properties: ${recommenderId} - ${JSON.stringify(recommenderPropertyResponse.data)}`, ); return recommenderPropertyResponse.data; } // Method to process an Activity Analysis // This is a default provided implementation protected async instanceContextBuilder(recommenderId: string): Promise<RecommenderBaseInstanceContext> { const recommenderProps = await this.fetchRecommenderProperties(recommenderId); const context: RecommenderBaseInstanceContext = { properties: new PropertiesWrapper(recommenderProps), }; return context; } protected async getInstanceContext(recommenderId: string): Promise<RecommenderBaseInstanceContext | null> { if (!this.pluginCache.get(recommenderId)) { void this.pluginCache.put( recommenderId, this.instanceContextBuilder(recommenderId).catch((err) => { this.logger.error(`Error while caching instance context: ${(err as Error).message}`); this.pluginCache.del(recommenderId); throw err; }), this.getInstanceContextCacheExpiration(), ); } return this.pluginCache.get(recommenderId); } // To be overriden by the Plugin to get a custom behavior protected abstract onRecommendationRequest( request: RecommenderRequest, instanceContext: RecommenderBaseInstanceContext | null, ): Promise<RecommendationsWrapper>; private initRecommendationRequest(): void { this.app.post( '/v1/recommendations', this.asyncMiddleware(async (req: express.Request, res: express.Response) => { if (!this.httpIsReady()) { const msg = { error: 'Plugin not initialized', }; this.logger.error('POST /v1/recommendations : %s', JSON.stringify(msg)); return res.status(500).json(msg); } else if (!req.body || _.isEmpty(req.body)) { const msg = { error: 'Missing request body', }; this.logger.error('POST /v1/recommendations : %s', JSON.stringify(msg)); return res.status(500).json(msg); } else { this.logger.debug(`POST /v1/recommendations ${JSON.stringify(req.body)}`); const recommenderRequest = req.body as RecommenderRequest; if (!this.onRecommendationRequest) { const errMsg = 'No Recommendation request listener registered!'; this.logger.error(errMsg); return res.status(500).json({ error: errMsg }); } const instanceContext: RecommenderBaseInstanceContext | null = await this.getInstanceContext( recommenderRequest.recommender_id, ); const pluginResponse = await this.onRecommendationRequest(recommenderRequest, instanceContext); this.logger.debug(`Returning: ${JSON.stringify(pluginResponse)}`); return res.status(200).send(JSON.stringify(pluginResponse)); } }), ); } }