⛅ Key-Value Storage With Cloudflare Workers KV (lesson 4)

Search for a command to run...

No comments yet. Be the first to comment.
Turn any website into an Installable App How I make web apps that install to the home screen (Android and iOS), launch full-screen (not in-browser), work offline, and offer a first-class in-app Instal

Type Narrowing allows the IDE (development environment) to narrow down the object type, from a union type, to a more specific type. Bullsh*t Example In this bullsh*t example, value is the union type string | number, meaning it can either be a string ...
There is still a lot of work to be done, but I finally have something "playable" 🔥 I would describe it as a mashup of Mine Sweeper and a rogue-like dungeon crawler RPG. That's right! The first playable demo is up! The game is still in active develo...

I recently added some dialog options for my indie game, Dungeon Sweeper: A Knights Adventure and wanted to create a TypeWriter effect for the dialog text. This technique works well for monospaced fonts and may not work for variable-width fonts. Fail...

TL;DR: I discuss adding intuitive features, dealing with Phaser quirks such as a tween memory leak and scaling issues, managing screen size, and creating an executable for a demo. I express my struggle with the less enjoyable parts of game developmen...

Serverless key-value storage or KV provides an easy way to store / retrieve data for your Cloudflare Workers. Best of all, Cloudflare has recently introduced a FREE tier for KV!
Workers KV reads respond incredibly fast. According to Cloudflare, as quickly as a cached static file would.
Workers KV is an eventually-consistent database. Changes may take up to 60 seconds to propagate (though in my experience it's much less). This means KV cannot be used in applications that require atomic transactions.
Workers KV is a key-value storage. Typical of KV storage solutions, there is no search. But there are list operations.
For this lesson, we will be using Cloudflare KV to put a key, get a key, and list keys.
In case you haven't been following along with the previous lessons (you don't have to), you can start here:
# continue where we left off
$ git clone https://github.com/joelnet/cloudflare-worker-website.git
$ cd cloudflare-worker-website
$ git checkout f6a224b37010d76d694320d4748ac07cb75f7369
$ npm ci
Namespaces are a way to segregate KV stores. This is useful if you run many applications under Cloudflare or separation within an application. For example, you might want to create LOGINS and PROFILES Namespaces. You could also do this with a key prefix like logins:<login> or profiles:<profile>.
A Namespace can be created within the Cloudflare website or with the wrangler CLI.
I'm going to create a new Namespace called FILES.
$ wrangler kv:namespace create "FILES"
The output should look something like this. Be sure to paste that bottom piece into your wrangler.toml.
🌀 Creating namespace with title "my-website-FILES"
✨ Success!
Add the following to your configuration file:
kv_namespaces = [
{ binding = "FILES", id = "529b4c9be8b344f59adfe89cc9765879" }
]
Add an ESLint Global by opening .eslintrc.yml. This will prevent ESLint from complaining about the FILES global.
globals:
FILES: readonly
The plan is to create 3 files. One each to read, write, and list the keys. Then use KV to store markdown files and then display them as HTML.
First, setup the routing to the new files.
Open src/index.js and add the imports.
import filesPost from './pages/files.post'
import files from './pages/files'
import filesList from './pages/files.list'
Then add a new routes. /? is RegEx for optional /. .+ is RegEx for one or more character.
router.post('/files/?', () => filesPost(request))
router.get('/files/.+', () => files(request))
router.get('/files/?', () => filesList(request))
Create src/pages/files.post.js. To create a key use the format: await NAMESPACE.put(key, value).
import { htmlResponse } from '../lib/responses'
const filePost = async request => {
const { filename, contents } = await request.json()
await FILES.put(filename, contents)
return htmlResponse('SUCCESS')
}
export default filePost
Keys can auto-expire by setting the expiration. Expiring Keys
Create src/pages/files.js. Reading a key uses the format: await NAMESPACE.get(key).
Note: There are more sophisticated ways to pull the filename off the URL, I'm using substring for the simplicity of this demo.
import marked from 'marked'
import { htmlResponse } from '../lib/responses'
import marked from 'marked'
import { htmlResponse } from '../lib/responses'
const files = async request => {
const url = new URL(request.url)
const id = url.pathname.substring(7)
const file = await FILES.get(id)
const html = marked(file)
return htmlResponse(html)
}
export default files
Create src/pages/files.list.js. The list uses the format: await NAMESPACE.list().
import { htmlResponse } from '../lib/responses'
const fileToLi = file => `
<li>
<a href="/files/${file.name}">${file.name}</a>
</li>
`
const fileList = async () => {
const files = await FILES.list()
const lis = files.keys.map(fileToLi).join('')
return htmlResponse(`<ul>${lis}</ul>`)
}
export default fileList
Lists also support paging and listing by prefix. Check the docs for more on lists.
Using the same pattern, implement a delete with the method await NAMESPACE.delete(key).
Implement pagination on the list page to support > 1000 entries.
Experiment with Expiring Keys.
Refer to the API for reference.
We used Workers KV to create a file upload to upload markdown files as well as display those markdown files as HTML. As a bonus there is a page that lists the FILES uploaded.
Browse the repository at this point in history.
Subscribe to my Newsletter to continue learning about Cloudflare Workers!
Cheers 🍻