Implement an RSS feed from JSON to XML in Gatsby.js

June 28, 2020 - rss xml json api nodejs - 6 min read

Implementing a site-wide RSS feed in Gatsby can be done very easily. I can recommend implementing the officialĀ Gatsby feed plugin.
In this tutorial, I want to show you how you can implement an RSS feed for a specific URL or page. In my case, the data for the RSS feed was provided to me via a REST API endpoint that returned JSON.

šŸ’”This tutorial assumes you already have a Gatsby site setup and running. If you are new to Gatsby, I can highly recommend theĀ Gatsby docsĀ to get started.

Here are the steps that I am going to walk you through in detail in this tutorial:

ā€” Test your API endpoint with `Postman`
ā€” Call JSON in /gatsby-node.js with `Axios`
ā€” Shape JSON by turning it into a JavaScript Object
ā€” Convert the new object to RSS XML with `jstoxml`
ā€” Use fs from Node.js to create a new file rss.xml
ā€” Test your new RSS feed with an RSS validator

Without further ado, letā€™s get started šŸ™Œ

The first step is to call the API endpoint and make sure that it returns the correct JSON.Ā PostmanĀ is an excellent tool to test your REST API endpoint.

It is as easy as creating a new ā€˜GETā€™ Request and inserting the endpoint. If your endpoint requires authentication you can read more about how to authenticate in Postman in theĀ Postman Learning Center.

GET Request to API endpoint returning JSON in Postman

Gatsby APP

/gatsby-node.js

Once you verified that the correct data is being returned from the API endpoint, navigate to yourĀ /gatsby-node.jsĀ file. This file contains code that runs when building your site. You can useĀ Gatsby Node APIsĀ to add code and control your sitesā€™ data. For my RSS feed, I am going to use theĀ OnPostBuild APIĀ to call my code at the end of the build process, after everything else has been built.

The first step is to call your API data usingĀ Axios. You can install Axios by runningĀ $ npm install axiosĀ in your terminal, and then you require it at the top of our file:

const axios = require('axios').default;
exports.onPostBuild = async () => {
  const rssFeed = () => axios.get('<your API endpoint>');
  const res = await rssFeed();
  // add code below into this function in chronological order
}

To test your implementation, build your app withĀ $ gatsby build && gatsby serveĀ to run a production build. You can also console.log your API endpoint results to make sure that your code is working.

JSON to XML

Shaping JSON

The syntax for an RSS feed is very specific XML. The code below is taken from this articleĀ W3Schools RSS. It shows the XML syntax that you require for the RSS feed to be valid šŸ„

<channel>
  <title>W3Schools Home Page</title>
  <link>https://www.w3schools.com</link>
  <description>Free web building tutorials</description>
  <item>
    <title>RSS Tutorial</title>
    <link>https://www.w3schools.com/xml/xml_rss.asp</link>
    <description>New RSS tutorial on W3Schools</description>
  </item>
  <item>
    <title>XML Tutorial</title>
    <link>https://www.w3schools.com/xml</link>
    <description>New XML tutorial on W3Schools</description>
  </item>
</channel>

As you can see in the example above, we need keys that are called ā€˜itemā€™ and then within that always keys with ā€˜titleā€™, ā€˜linkā€™, and ā€˜descriptionā€™. There are more valid keys you can useĀ in the Channel and the Item Element.

The JSON data returned from your API might not take that XML syntax into account and the keys might not match. This was my case so I first had to shape the JSON to rename the keys to match the keys for the RSS feed. Here is theĀ StackoverflowĀ post that helped me write the code below āœŒļø

const JsonToObject = res.data.glossary.map(
  (obj) => ({
    item: {
      title: obj.Vendor,
      link: obj.Website,
      description: obj.Purpose,
      category: obj.Country,
    },
  }),
);

šŸ’” When you check your response.data from your API call, you can map over the array of JSON objects, and with JavaScript change the values to the corresponding XML value.
You can take a look at my JSON in the Postman screenshot at the beginning of this tutorial for reference.

Convert your new object to XML with jstoxml

Now that you have the correct values in place, you can convert your JavaScript object to XML for the RSS feed. I chose to use theĀ jstoxmlĀ plugin because it offers RSS feed support.

You can install the plugin with npmĀ $ npm install jstoxmlĀ and require it at the top of the file above Axios.

const { toXML } = require('jstoxml');
const axios = require('axios').default;

Next, you adjust your data for the plugin according to their specifications. This is what it looks like for me:

const xmlOptions = {
  header: true,
  indent: '  ',
};
const feed = await toXML({
  _name: 'rss',
  _attrs: {
    version: '2.0',
  },
 _content: {
    channel: [
    {
      title: 'Example title',
      link: '<Link to RSS feed>',
      description: 'Example description',
    },
    JsonToObject,
    ],
  },
}, xmlOptions);

What I do here is that I first provide aĀ title,Ā link,Ā andĀ descriptionĀ to theĀ ChannelĀ Element and then pass in my `JsonToObject` variable, which holds the shaped js object. The objects will be mapped over inside the JsonToObject function and the plugin will wrap each of the objects intoĀ ItemĀ Elements for you.

The jstoxml plugin will now turn your data into valid RSS XML formatšŸ‘

Gatsby Static folder is where your RSS feed will live

The last step is to create a static file to print your new XML feed. If your RSS feed is supposed to live at the pathĀ www.example.com/test/list/rss.xml,Ā you can create a folder inside yourĀ Gatsby static folderĀ calledĀ test, and a folder withinĀ testĀ calledĀ list. Keep the list folder empty.
This folder structure inside theĀ staticĀ folder will create the first part of the path.

/rss.xml

You are now going to programmatically create anĀ rss.xmlĀ file within theĀ listĀ folder by usingĀ fs.writeSync MethodĀ from Node.js.Ā GeeksForGeeksĀ has an excellent post on this method.

The fs.writeSync Method takes two or more arguments.

  • The first argument creates a file at a specified location
  • The second argument writes content into the newly created file

Here is my code:

try {
  fs.writeFileSync('<absolute path>/test/list/rss.xml', feed);
} catch (err) {
  console.log('Cannot write file!!!', err);
}

**Note:**šŸ‘‰ Do not forget to specify your rss.xml file so that it can be created in your folder. It is important to define the absolute path.

The second argument is the content for the file. In my case,Ā feedĀ is the variable I store my new XML data in (see code block above).

This method will overwrite an existing rss.xml file with new data every time it runs, which is after every build for us.

You can now run your Gatsby app withĀ gatsby build && gatsby serveĀ and you will see the rss.xml file being created. You can now navigate to the URL you specified for your RSS feed to see it.

Pro Debugging TipĀ šŸ™‹
If you get an error message that the file already exists, try closing and re-opening your terminal. If that does not work, try including this code into your fs method { encoding: ā€˜utf8ā€™, flag: ā€˜wā€™ } like so:

fs.writeFileSync('<absolut path>/test/list/rss.xml', feed, , { encoding: 'utf8', flag: 'w' }

Testing your RSS Feed

In order to test your RSS feed, I recommend pasting the URL or your XML Code directly into a RSS checker such as theĀ W3C ValidatorĀ šŸš€

And that completes my tutorial šŸŽ‰ Congrats, you now have a fully valid RSS feed at a specific URL


Profile picture

Written by Christina Hastenrath
Software Engineer @Postman šŸ‘©ā€šŸš€ Follow me on Twitter for more tech content šŸ™Œ

Ā© 2021, Built with šŸ’š by Christina Hastenrath