Creating an RSS Feed Custom Data Source for PnP Search

Introduction

In this blog post, we will walk through the steps to create a custom data source for PnP Search that fetches data from RSS feeds. We will use the RssDataSource.ts file as our reference.

Read more about how to create custom data sources for the PnP Search Web Part here: https://microsoft-search.github.io/pnp-modern-search/extensibility/custom_data_sources/

Prerequisites

  • Basic understanding of TypeScript and React
  • Familiarity with SharePoint Framework (SPFx)
  • Node.js and npm installed on your machine
  • SharePoint Online site

Setting Up the Project

First, set up a new SPFx project using the Yeoman generator. Choose Library as the project type and React as the framework

yo @microsoft/sharepoint

Creating the RSSDataSource

Create a new TypeScript file for your custom data source, e.g., RssDataSource.ts.

Implementing the RSSDataSource

Implement the RSSDataSource by following these steps:

Import Dependencies

import { BaseDataSource, IDataContext, IDataSourceData } from "@pnp/modern-search-extensibility";
import { PageContext } from "@microsoft/sp-page-context";
import { RssService, IRssService } from "../../../common/services";
import { ServiceScope } from "@microsoft/sp-core-library";
import { IPropertyPaneGroup, PropertyPaneDropdown, PropertyPaneTextField, PropertyPaneToggle } from '@microsoft/sp-property-pane';
import { HttpClient } from "@microsoft/sp-http";

Define the Interface

export interface IRSSDataSourceProps {
  siteUrl: string;
  rssTitle: string;
  rssTitleLink?: string;
}

Define the RSSDataSource Class

export class RSSDataSource extends BaseDataSource<IRSSDataSourceProps> {

  private _rssService: IRssService;
  private _pageContext: any;
  private _httpClient: HttpClient
  private numberOfItems: number;

  public constructor(serviceScope: ServiceScope) {
    super(serviceScope as any);

    serviceScope.whenFinished(() => {

      // Get the page context and httpClient from the service scope
      this._pageContext = this.serviceScope.consume(PageContext.serviceKey as any) as any;
      this._httpClient = serviceScope.consume(HttpClient.serviceKey);
    });
  }

  async getData(dataContext?: IDataContext): Promise<IDataSourceData> {

    const rssFeedUrl = this.properties.siteUrl;
    // initialize the dataservice
    this._rssService = new RssService(this._httpClient);
    
    let rssItems;
    try {
      rssItems = (await this._dataService.getRssItems(rssFeedUrl)).slice(0,dataContext.itemsCountPerPage);
    } catch (error) {
      console.error('Failed to fetch RSS items:', error);
    }

    const data: IDataSourceData = {
      items: rssItems,
      rssTitle: this.properties.rssTitle,
      rssTitleLink: this.properties.rssTitleLink
    };
    this.numberOfItems = rssItems.length;
    return Promise.resolve(data);
  }

  public getPropertyPaneGroupsConfiguration(): IPropertyPaneGroup[] {
    return [
      {
        groupName: "RSS data source",
        groupFields: [
          PropertyPaneTextField("dataSourceProperties.siteUrl", {
            label: "Configure RSS-data source",
            description:"Address for RSS feed"
          }),
          PropertyPaneTextField("dataSourceProperties.rssTitle", {
            label: "Titel för RSS Flöde",
          }),PropertyPaneTextField("dataSourceProperties.rssTitleLink", {
            label: "Title link",
            description:"Link to go to when clicking the main header"
          }),
        ]
      }
    ];
  }

  getItemCount(): number {
    return this.numberOfItems;
  }
}

The RssService.ts class looks like the following

IMPORTANT! This code assumes that the response JSON contains an array of “items”, but this may differ depending on the schema for the RSS Flows you want to connect to.

import { HttpClient } from '@microsoft/sp-http';
import * as _ from 'lodash';

export class RssService  {

  private _httpClient: HttpClient;

  constructor(httpClient: HttpClient) {
    this._httpClient = httpClient;
  }

  // Get RSS feed items
  public async getRssItems(rssFeedUrl: string): Promise<any[]> {
    try {
      const response = await this._httpClient.get(rssFeedUrl, HttpClient.configurations.v1);

      if (!response.ok) {
        console.error(`Failed to fetch RSS feed. Error: ${response.statusText}`);
        return []; // or handle the error differently
      }

      const rssJson = await response.json();

      if (rssJson) {
        const items = rssJson.items;
        return items;
      } else {
        console.error('Empty RSS feed response');
        return []; // or handle the case of empty response differently
      }
    } catch (error) {
      console.error('Error fetching RSS feed:', error);
      return []; // or handle the error differently
    }
  }
}

Testing the Data Source

Deploy the custom data source to your SharePoint Online site and test its functionality.

Conclusion

In this post, we have created a custom data source for PnP Search that fetches data from RSS feeds. This allows you to integrate external RSS feed data into your SharePoint search experience.

Disclaimer

The code and instructions provided in this blog post are for educational purposes only. While every effort has been made to ensure the accuracy and functionality of the code, the author and publisher assume no responsibility for any errors or omissions. Use the code at your own risk and always test thoroughly in a development environment before deploying to production.

Leave a comment