Building a pageview counter with Deta.sh Micros and Base database

image by Paul Cezanne

Building a pageview counter with Deta.sh Micros and Base database

serverless for pageview

I’m migrating/spreading all my APIs from Heroku to the clouds with serverless platforms. Here’s a rough idea that implements a simple pageview counter with Deta.sh Micros (Node.js as the runtime engine) and Base database (of course, without any charges 🥳).

Before we start, some limitations of the Deta platform need to be noted.

  • Deta Micros1
    1. Micros support the following runtimes:
      • Nodejs 12.x and 14.x
      • Python 3.7, 3.8, 3.9
    2. Timeout after 10s.
    3. 128 Mb of RAM for each execution.
    4. HTTP payload size limit to 5.5 Mb.
    5. Not support connecting to MongoDB, also NOT works well with RDMBS…
    6. Source code and assets limited to 250 Mb.
  • Deta Base2
    1. It’s a NoSQL database.
    2. Up to 1Mb of data retrieved with each query.

For such a simple pageview counter, all these limitations won’t cause any problems.

Okay, let’s start our journey.

Install and configure the Deta CLI

First, install the Deta CLI.

For macOS and Linux:

curl -fsSL https://get.deta.dev/cli.sh | sh

For Windows PowerShell:

iwr https://get.deta.dev/cli.ps1 -useb | iex

This will download the binary which contains the CLI code. It will try to export the deta command to your path.

Once you have successfully installed the Deta CLI, you’ll need to log in to Deta with your credentials.

From your Terminal:

deta login

Create a micro project

Deta Micros (micro servers) are a lightweight but scalable cloud runtime tied to an HTTP endpoint. They are meant to get your apps up and running blazingly fast. Focus on writing your code and Deta will take care of everything else.

Initialise the project

To create a Micro, navigate in the Terminal to a parent directory and type:

deta new --node pageview

This will create a new Node.js Micro called pageview which will contain an index.js file.

Enter the pageview directory, and setup the dependencies:

cd pageview

yarn init -y

yarn add express

This initialised the project with the Express.js framework, with the following contents in the index.js file:

const express = require('express');

const app = express(); 

app.get('/', async (req, res) => {
  res.send('Hello World')
});

module.exports = app;

Don’t rename the filename of index.js and the application name of app as they’re required by the Deta Micros.

Then, just coding as normal Express app…

Deploy the project

After updating the dependencies, use deta deploy to update the Micro in the cloud:

deta deploy

Well, the starter project is up and running 🌟. We can now visit the endpoint (use deta details to find the URL).

Currently, only the GET / router is implemented, which just returns a string Hello World.

The workflow is just like this, coding in the index.js file and then deploying to the cloud with deta deploy. Of course, you can spread the middlewares, routers, controllers, et al. in different folders and files as usual, here we just condense on the single index.js file for simplicity.

Connecting the Base database

Deta Base is a fully-managed, fast, scalable and secure NoSQL database with a focus on end-user simplicity. It offers a UI through which you can easily see, query, update and delete records in the database.

Okay, still in the pageview folder, add the deta package into our project:

yarn add deta

Since we’re connecting the Base database from the Micros, we don’t need to care about the credentials for the connection, valid keys are pre-set in the Micro’s environment.

To create a database named pageview, just update the index.js as:

const express = require('express');
const { Base } = require('deta');

const app = express(); 

// connect or create a database
const pv = Base('pageview');

// ...

Fetch and update a pageview counter

Here, we’re going to set a POST router to receive the JSON data, update the database and then return the updated data to the client (the website).

Inside the Base database, we can use the url string as the unique key to store and query the data3. But you can also format the url to MD5 string or anything compatible as the identifying key, that’s really up to you.

const express = require('express');
const { Base } = require('deta');

const app = express(); 

// parse json data from request.body
app.use(express.json());

// CORS...
app.use((_req, res, next) => {
  // you should know what you're doing here...
  // more information at
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  next();
});

// connect to the 'pageview' database in Base
const pv = Base('pageview');

app.post('/', async (req, res) => {
  try {
    const { url, title } = req.body;
    const key = url;

    // check the record is existing in the database
    const record = await pv.get(key);

    // the default counter/hits number
    let hits = 1;

    // if the record exits, update the counter on 'hits' property
    if (record) { hits = record.hits + 1 }

    const data = { title, url, hits };

    // put updated data to the database
    const updatedRecord = await pv.put(data, key);

    // return the updated data as a JSON object
    // structured as { title, url, hits }
    return res.status(200).json(updatedRecord);
  } catch (err) {
    return res.status(500).send(err.message);
  }
});

// export 'app'
module.exports = app;

On the client-side, we can use the Fetch API to send data (the url and title) to the endpoint (by deta details) and get the most updated pageview hits whenever a visitor hits a page 🎉.

For example:

const data = { url: document.URL, title: document.title };

// your deta micro url
const detaURL = 'https://xxxx.deta.dev';

fetch(detaURL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
  const { hits } = data; // the pageview number here...
})
.catch((error) => {
  console.error('Error:', error);
});

That’s all about this simple pageview counter with Deta.sh services. You can add more layers about security and functions with all the free resources.

In the real implementation on this Jekyll site, I’m using RudderStack to capture the pageview events (using Beacon API) and push them to the Deta Base database in the cloud. Thus, on the frontend, just need to GET the data with a unique id to retrieve the pageview counts. The id is generated with url and marked with MD5:

{{ page.url | prepend: site.url | replace: 'index.html', '' | md5 | slice: 0, 14 }}
# output like
# 89a323f52193af

In the Micro, just add a new GET router like app.get('/:id', ...) for fetching data. Also, the recent visits are returned from the same GET request, see it’s live on the sidebar… 👉️

Conclusion

The Deta.sh platform is great to serve microservices without any charges, just like the one about the pageview counter presented in this post. Don’t hesitate to use these resources to implement your ideas.

THE END
Ads by Google

林宏

Frank Lin

Hey, there! This is Frank Lin (@flinhong), one of the 1.41 billion . This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Hands on IBM Cloud Functions with CLI

Tools

2020.10.20

Hands on IBM Cloud Functions with CLI

IBM Cloud CLI allows complete management of the Cloud Functions system. You can use the Cloud Functions CLI plugin-in to manage your code snippets in actions, create triggers, and rules to enable your actions to respond to events, and bundle actions into packages.

Using Liquid in Jekyll - Live with Demos

Web Notes

2016.08.20

Using Liquid in Jekyll - Live with Demos

Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.

Setup an IKEv2 server with strongSwan

Tutorials

2020.01.09

Setup an IKEv2 server with strongSwan

IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunnelling between networks. It is developed by Microsoft and Cisco (primarily) for mobile users, and introduced as an updated version of IKEv1 in 2005. The IKEv2 MOBIKE (Mobility and Multihoming) protocol allows the client to main secure connection despite network switches, such as when leaving a WiFi area for a mobile data area. IKEv2 works on most platforms, and natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary.