Using @elianvancutsem/mostvisitedpages as a serverless function
I’ve moved from a regular RESTful API to serverless functions. Here is a little guide and explanation on why & how I did that.
So the @elianvancutsem/mostvisitedpages
is a NPM package I wrote sometime ago to basically return your most visited pages fetched from Google Analytics.
At the time I wrote a complete API in NestJS with just a simple /analytics
endpoint which would handle the Google Analytics part. (there were of course some other endpoints as well, but I won’t go deeper into them right now, maybe in the future…)
Why?
My main reasons for migrating to serverless functions instead of a full fetched container are
- no shared resources anymore
- code splitting / single responsibility
- better DX
- way, way faster
- Lower costs
I also migrated my website itself from Google Cloud Storage to Firebase hosting, which is basically the same functionality, but Firebase has the advantage of managing everything on a smaller interface.
That includes analytics, storage, functions, databases, authentication and hosting. All of those on one page with a quick overview. This is (speaking for myself here) a better developer experience.
Of course, if you’re in need of a bigger project, Google Cloud is still the way to go.
Astro
Now, one of the other reasons I wanted to migrate to serverless functions, is that my main website uses Astro. Astro has the option to fetch API’s at build-time instead of every page load. So for data that doesn’t change frequently, like your most visited pages, this is ideal. If you then only need to fetch a simple function instead of spinning up a whole container, you save on resources, time and money.
Sounds great no?
initiating functions
The functions I’m writing here, are all written in JavaScript (or TypeScript for that matter), but be aware that there are more function runtimes on Google Cloud (but not Firebase), like Go, Java or even PHP. (full list here)
You can setup a new functions project by running:
npm i -g firebase-tools
firebase init --functions
This will ask you some questions, like JavaScript or TypeScript, what project and so on.
If you’re not yet authenticated in firebase, run firebase login
before initializing the functions.
Writing functions
Basically, each exported function from a file (like index.js
), is deployed as a separate Firebase function.
import { HttpsFunction, https, Request, Response } from "firebase-functions";
export const yourFunction: HttpsFunction = https.onRequest(
async (req: Request, res: Response) => {
// our main code goes here
res.status(200).send();
},
);
A little trick to manage more functions, without having them all in one file, is to do the following:
// analytics.js
export const analytics = https.onRequest(
async (req: Request, res: Response) => {
// analytics endpoint
res.status(200).send();
}
);
// technologies.ts
export const technologies = https.onRequest(
async (req: Request, res: Response) => {
// technologies endpoint
res.status(200).send();
}
);
// index.js
import { technologies } from "./technologies";
import { analytics } from "./analytics";
export { technologies, analytics };
These functions will get deployed as two separate Firebase functions.
Testing functions
Functions can be tested locally by running the npm run serve
command.
This will spin up some local ports with your functions, logs and an emulator to manage and overview it all.
Really neat!
Deploying functions
firebase deploy --only functions
keep in mind that the --only functions
here, is used to only deploy functions in case you have configured other firebase things, like storage, as well.
Till the next!