Using Cloudflare Workers KV Storage in action

Using Cloudflare Workers KV Storage in action

dev.to - Jan 24

Cloudflare workers is a service that lets us to deploy to the Cloudflare network distributed around 200 cities around the world. With this we are using the edge functions which servers us very low latency and is near to us geographically distributed.

Among many of the services provided by Cloudflare we are focusing on Workers Key Value(KV) Store. We will bring here official KV definition from Cloudflare docs

Workers KV is a global, low-latency, key-value data store. It stores data in a small number of centralized data centers, then caches that data in Cloudflare’s data centers after access. KV supports exceptionally high read volumes with low latency, making it possible to build highly dynamic APIs and websites that respond as quickly as a cached static file would. While reads are periodically revalidated in the background, requests which are not in cache and need to hit the centralized back end can see high latencies.

Official docs

What will we build

We will build a simple API where we will be interacting with the KV to get all KV, get a one KV, put new KV storage.

We will build a mini subscription application which lets us store the email, status(free/premium), id in a KV Store. This will help us to know which users belongs to the free plan or premium plan.

We can start by installing Wrangler if you dont have it in your local machine. Its a CLI with helps us to create workers project locally.

npm install -g wrangler
Enter fullscreen mode Exit fullscreen mode

After installation we are ok to create our worker project. Where we will be using a Javascript to write all the logic currently. But you can use the official templates provided with many launguage as your choice.

wrangler init project-name
Enter fullscreen mode Exit fullscreen mode

We can now start by creating a new folder and name it utils. Here we can add any functionalities which can help us interact with the KV methods.

Installing dependencies

We will use a bare minimum dependencies as possible. Lets add two packages with command below

npm i itty-router nanoid
Enter fullscreen mode Exit fullscreen mode

itty-router is the routing library which we will use.
nanoid is the library we will use for generating unique ids.

Generating new KV Namespace

To get started with KV Storage you need a namespace to be generated. Below are the commands you will need.

npx wrangler kv:namespace create "SUBSCRIPTIONS"

npx wrangler kv:namespace create "SUBSCRIPTIONS" --preview 
Enter fullscreen mode Exit fullscreen mode

The--preview option informs Wrangler it’s for preview only, which is specifically for development mode.

You might need to create a cloudflare account to generate your workers id. You can get it from thedashboard.

Below is the example of updated wrangler.toml file with the information needed

name = "kv-worker-demo"
type = "webpack"
main = "src/index.js"
account_id = "**********"
workers_dev = true
compatibility_date = "2023-01-21"
webpack_config = "webpack.config.js"
kv_namespaces = [
    { binding = "SUBSCRIPTIONS", id = "*********", preview_id = "*********" }
]
Enter fullscreen mode Exit fullscreen mode

Creating routes

import { Router } from "itty-router";

const router = Router();

router.get("/api/subscriptions", async (req) => {
  return new Response("Workers running...", { status: 200 });
});

router.get("*", () => new Response("Not found", { status: 404 }));

export const handleRequest = (request) => router.handle(request);
Enter fullscreen mode Exit fullscreen mode

We will make the use of router from our itty-router library. and create a get request route for two basic endpoint where we have a general route with a astrix and /api/subscribers to interact with our workers listening.

Get all subscribers

To get all the records of the subscribers we could make the use of the namespace we created and return empty if we dont find one.

import { KV_KEY_ID } from '../handler'

export const getAllSubscriptions = async () => {
  let subscriptions = await SUBSCRIPTIONS.get(KV_KEY_ID)
  if (subscriptions === null) {
    return []
  }
  return JSON.parse(subscriptions)
}
Enter fullscreen mode Exit fullscreen mode
export const KV_KEY_ID = 'subs'

router.get('/api/subscriptions', async req => {
  const allSubs = await getAllSubscriptions()
  return new Response(JSON.stringify(allSubs))
})
Enter fullscreen mode Exit fullscreen mode

Creating new subscriber

To create a new subscriber we need a POST request. This would first take in a request body and calls a function addSubscriptions taking in the content as a parameter.

router.post('/api/subscriptions', async req => {
  let content = await req?.json?.()
  if (content == undefined) {
    return new Response('Please provide a request body.')
  }
  content['id'] = nanoid()
  let subs = await addSubscriptions(content)
  return new Response(JSON.stringify(subs))
})

Enter fullscreen mode Exit fullscreen mode

We need to create a addSubscriptions function which will make a call to our previous function and pushes a new item into that array.

Lastly we need to make a PUT request to our worker to notify the change with a .put() method available to us.

export const addSubscriptions = async (sub) => {
  let subscription = await getAllSubscriptions()
  subscription.push(sub)
  await updateSubscriptions(subscription)
  return sub
}

export const updateSubscriptions = async (sub) => {
  await SUBSCRIPTIONS.put(KV_KEY_ID, JSON.stringify(sub))
}
Enter fullscreen mode Exit fullscreen mode

Getting one subscriber

We can also get the request parameter and find the needed KV from our store.

And finally return a stringified version of the id that is passed in to us from the request object.

router.get('/api/subscriptions/:id', async req => {
  let allSubs = await getAllSubscriptions()
  let subID = allSubs.find(a => a['id'] == req.params?.id)
  if (!subID) {
    return new Response('This ID is not matched')
  }
  return new Response(JSON.stringify(subID))
})

Enter fullscreen mode Exit fullscreen mode

This is how we can make the use of Cloudflare KV for our data storage solution makes it handy. We used a multiple, kv_namespaces accepts an array of objects.

We could add still more functions where we could use the delete, listing only keys, Time to live(TTL), Expiring keys and many awesome features baked in.

You can learn more from here

You can find the complete code repository here.

Happy coding!

Reading references

Workers KV
How KV Works
Durable Objects
https://youtu.be/dei8fOR_Of8

MORE ARTICLES