Next.js + serverless personal webpage in a couple of hours — Pull Medium posts with Serverless Function (Part 6)
What I want to achieve is to provide a more seamless experience when users click on the “Blog” button on my webpage. I want to display in my webpage a list of recent posts that I have published on Medium and keep them up to date automatically.
This is part 6 of a series of posts I made for documenting my journey of setting up my personal webpage in an evening:
Part 1: Development Environment Setup
Part 2: Purchasing your own domain name and set up email forwarding
Part 3: Bootstrapping the app with Next.js
Part 4: Deploying to Production with Vercel
Part 5: Integrate your contact form with Formspree
Part 6: Pulling blog posts from Medium with a serverless function(📍 You are here)
Pulling data from Medium’s RSS feed (120 mins)
A natural approach is to pull data from Medium is to use their REST API. After some research, I concluded that Medium’s API only provide interfaces for creating publications and not fetching publications. You may ask why, but I guess one obvious answer is that they want to readers to read from their platform instead of consuming content from third-party services.
However, Medium does provide an RSS feed that contains excerpts for an author’s publications at https://medium.com/feed/@author-handle. This will work - we just need to parse the RSS feed (which is in XML)and format the data in JavaScript right?.
CORS problem
You may be tempted to fire an XHR request using JavaScript from the client-side to retrieve data from Medium’s RSS endpoint. This unfortunately will fail as the response from the Medium RSS endpoint does not include the Access-Control-Allow-Origin
header. All modern broswers respect the CORS policy and will refuse to let JavaScript code access those responses.
Any workarounds?
One option is to use a free/public CORS proxy which acts as a middleman and adds the Access-Control-Allow-Origin
to the response. This approach puts a lot of trust into the proxy provider and your webpage is now also dependent on its availability. cors-anywhere used to be an open proxy on Heroku. This is no longer the case as of Jan 2021.
This brings us to two options:
- Run our own CORS proxy
- Setup an API Gateway using a serverless function
Running our own CORS proxy is more involved in terms of the infrastructure and cost. I’m going with Option #2. There are a few options when it gets to serverless functions, AWS lambda being the most popular. Yet, since our deployment already lives in the Vercel ecosystem, it makes sense to use serverless functions provided by Vercel as well.
Let’s start with the hello world function
When you created your app with create-next-app
, it already gives you an example hello world function in the /api
folder of the project root. By default, any functions under /api
are automatically hosted and exposed by Vercel with a HTTP endpoint.
Navigate to https://yourdomain.com/api/hello, you should see the JSON response.
On Vercel, navigate to your deployment and go to Functions. It shows realtime logs for your serverless functions.
Testing your function locally
While it’s quick to deploy and test on Vercel. It’s still quicker if we are able to test the serverless functions locally when we are doing development. The Vercel CLI provides this functionality by replicating the production environment on Vercel. Install the CLI by running:
npm i vercel
Then instead of npm run dev
, start the local dev server by:
npx vercel dev
Under the hood it also use next dev
to watch for changes in your project directory, but you can now also invoke your functions by going to http://localhost:3000/api/hello
Dumping the Medium RSS feed in our function
Let’s do a proof of concept by creating a function to dump the entire RSS feed for my account https://medium.com/feed/@jeremy-chan
First we need some http client to fire the request from the serverless function. We are going to use axios
:
npm i --save axios
Vercel will automatically install dependencies in package.json
for your serverless function.
Now let’s write some code to dump data from the RSS feed:
Navigate to http://localhost:3000/api/medium and you should see the content of the XML dumped into the text
field of the JSON response.
Try deploying it on Vercel and see it live.
Converting XML to JSON
We can convert the XML response to JSON using the xml2js package.
npm i --save xml2js
Modify the code above to convert the XML to JSON and return in the response. We also selectively extracted only the information we need from the converted JSON to keep our response nice and clean.
Hit your API again and you should see the RSS feeds converted to JSON format like below:
Displaying the content in your webpage
With an API under the same domain name that proxies the Medium RSS XML and returns a nice JSON, we just need to glue the pieces together and render the “Blog” component in our UI using the API response.
Here we hit our API in the useEffect
function of the component. We pass an empty array []
as dependency for the function so useEffect
only runs once when the component is rendered. We save the posts fetched from the API into a local state and render it into a list of <div>
.
The end result looks like this. With serverless function the webpage is kept in sync whenever a new post is published.
Conclusion
This concludes the series. I’m happy with how much I’ve learned and achieved in an evening. I’m also impressed with the pleasant developer experience that Next.js and Vercel provide for deploying static webpages.
Total time spent: ~4 hours
Total expense: £10
Number of times getting stuck: 0
Part 1: Development Environment Setup
Part 2: Purchasing your own domain name and set up email forwarding
Part 3: Bootstrapping the app with Next.js
Part 4: Deploying to Production with Vercel
Part 5: Integrate your contact form with Formspree
Part 6: Pulling blog posts from Medium with a serverless function