How to cache a simple javascript array in Cloudflare and return it to Slack?

I am trying to create a Slack bot that will add a developer name to a release queue using a Cloudflare worker. Example: /releasenext <your name>, Slack bot will add you to the queue and will tell you who else is in that queue.

I would like to use Cloudflare cache to cache names coming from the POST request. So I am using a javascript array. I am trying to cache that array, and anytime somebody is adding their name to the queue, the Slack bot should reveal the persons already in the queue and the new person who added their name.

So far, I managed to create the communication between Cloudflare and Slack via a command on Slack /releasenext <your name>, and Slack answers me with: the next person to release is: <your name>.

I found the documentation and some examples but I am not understanding how it works exactly.

here is the documentation: How the Cache works · Cloudflare Workers docs

And here is my code:

const SLACK_TOKEN = "secret"
const BOT_NAME = "Deploy-bot 🤖"

let jsonHeaders = new Headers([["Content-Type", "application/json"]])


let resp

addEventListener('fetch', event => {
  event.respondWith(slackWebhookHandler(event.request))
  resp = fetch(event.request, { cf: {cacheEverything: true} })
  resp = fetch(event.request, { cf: { cacheTtl: 300 } })
})


// simpleResponse generates a simple JSON response 
// with the given status code and message.

function simpleResponse(statusCode, message) {

  let resp = {
    message: message,
    status: statusCode
  }

  return new Response(JSON.stringify(resp), {
    headers: jsonHeaders,
    status: statusCode
  })
}


// slackResponse builds a message for Slack with the given text
// @param {string} text - the message text to return

function slackResponse(text) {

  let content = {
    response_type: "in_channel",
    text: text
  }

  try {
    return new Response(JSON.stringify(content), {
      headers: jsonHeaders,
      status: 200
    })
  } catch (e) {
    return simpleResponse(
      200,
      "Sorry, I had an issue generating a response. Try again in a bit!"
    )
  }
}


// parseMessage parses the selected name from the Slack message.
// @return {string} - the name.

function parseMessage(message) {

  try {
    const name = message.get("text").trim()
    return {name: name}
  } catch (e) {
    return null
  }
}


async function addPersonToQueue(name) {

  try {

    let cachedResponse = false
    if (resp.headers.get("cf-cache-status").toLowerCase() === "hit") {
      cachedResponse = true
    }

    const nameQueue = []
    nameQueue.push({name: name}, {cached: cachedResponse})
    let output = nameQueue.map(item => {return item.name}).join(', ')
    return output
  } catch (e) {
    throw new Error(`could not fetch the selected name: ${e}`)
  }
}


// slackWebhookHandler handles an incoming Slack webhook and generates a response.
// @param {Request} request

async function slackWebhookHandler(request) {

  if (request.method !== "POST") {
    return simpleResponse(
      200,
      `Hi, I'm ${BOT_NAME}, a Slack bot for fetching the latest person name to release`
    )
  }

  let formData
  try {
    formData = await request.formData()
    if (formData.get("token").toString() !== SLACK_TOKEN) {
      return simpleResponse(403, "Invalid Slack verification token")
    } 
  } catch (e) {
      return simpleResponse(400, "could not decode POST form data")
  }

  try {
      let parsed = parseMessage(formData)
      if (parsed === null) {
        throw new Error("could not parse your message")
      }

      let reply = await addPersonToQueue(parsed.name)

      return slackResponse(
        `The next person to release is: *${reply}*`,
        `the cache is: ${reply.cached}`
      )
  } catch (e) {
      return simpleResponse(
        200, 
        `Sorry, I had an issue retrieving names from the release queue ${e}`
      )
    }
}

The error message I have now is

{"message":"Sorry, I had an issue retrieving names from the release queue Error: could not fetch the selected name: TypeError: Cannot read property 'get' of undefined","status":200}

The expected output is: The next person to release is: person1, <your name>.
Assuming that another person already added their name to the queue first.

Hey @emilie, sounds like a cool project!

I think your error is here:

if (resp.headers.get("cf-cache-status").toLowerCase() === "hit") {
  cachedResponse = true
}

While I see you’ve set up the resp variable at the top of the script, I don’t think that it has headers set on it yet. Give that a shot and let me know!

1 Like