In my last post I wrote about building a web worker to hit the dev.to API and render the list of posts that I've written:
Cloudflare Workers are the future! 🏗
Bryce Dorn ・ May 9 '22 ・ 2 min read
After publishing the article though, I noticed something: the /articles
API response didn't update & show my new post in the list! The data when directly hitting the endpoint in my browser was correct, but via fetch
it was outdated. This meant the response for the latter was being cached somewhere or was hitting a slower follower database. 🙁
The main difference between fetch
and my browser were request headers, specifically that my browser had a cookie
header with authentication information. I needed a way for the getPosts
function to send this cookie header so when I make a new post it shows up in my list!
Get cookie
header value 🍪
This step was the easiest: just hit any API endpoint and open developer tools. In Chrome you can do this by hitting ⌘+⌥+i (command+option+i). Then, open the Network tab and in the list of requests on the left select the articles
request (or whatever API endpoint you chose). If you don't see any requests just reload the page and it should appear.
It should display the Headers
tab by default, in which you can scroll down and see the list of Request Headers
tied to the request. We want the cookie
value, so copy its full value and keep it somewhere for later!
Note: looking at the
set-cookie
in login callback, the cookie expires after 2 weeks so this may only work until then (and the value will need to be refreshed).
Add a global value with esbuild 🧩
Thankfully esbuild supports a define
feature that can replace a global identifier with a constant value. This means setting a value (cookie) on process.env
and then use it in another function (fetch)! process.env
is Node's global environment object, so setting the value here will allow other files to natively reference it. This is what my build script ended up looking like:
const { build } = require('esbuild')
build({
...
define: {
'process.env.COOKIE': "my-cookie-value",
},
...
})
Then using the value in getPosts
:
const headers = {
cookie: process.env.COOKIE
}
const response = await fetch(url, { headers })
Ta-da! 🙌 If you replace "my-cookie-value"
with the value from the first step you should see up-to-date API data.
Make things secret 🤫
This cookie value shouldn't be seen by others! It's tied to your account and should be handled carefully. Values like this leaking to the wild are the cause of countless security breaches that still occur regularly, and there are entire projects dedicated to finding them.
So instead of storing the value directly in your build script, locally you can make an .env
file and put it there:
COOKIE="my-cookie-value"
Then, update the build script to import from process.env
:
define: {
'process.env.COOKIE': JSON.stringify(process.env.COOKIE),
},
Et voila, it's now hidden from prying eyes! Just don't commit .env
to git 😉 it can be stored secretly elsewhere for CI.
Integrate with GitHub Actions ⚙️
Only two steps left! This assumes you already have a deploy script that uses wrangler-action.
Secrets are how GitHub Actions handle environment variables; in workflow logs the value is masked. First, we need to add this secret to the action. To do this, navigate to your repository Settings:
Then under Security click Secrets > Actions:
And finally New repository secret:
For name type COOKIE
and for value use your header value from earlier. Then click "Add secret":
Then, it's just a matter of referencing this secret in the deploy
action and adding it to the env
:
- name: Publish
uses: cloudflare/wrangler-action@1.3.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
secrets: COOKIE
env:
COOKIE: ${{ secrets.COOKIE }}
This will add it to the env
, which will be picked up by esbuild, added to proces.env
then used in the fetch
!
And to dev.to admins: as far as I can tell this doesn't go against any terms, but let me know otherwise. The response is also edge cached so it shouldn't be repeating requests.
Hopefully this helps! It's super satisfying to be able to handle build/deploys completely via CI.