View on GitHub

til

A simple Today I Learnt

Accessing-Postgres-From-Cloudflare-Workers

Cloudflare has workers - a serverless platform that runs your code across its edge location. One thing, it doesn’t natively talk tcp yet which means accessing Postgres natively from a worker is not possible. However, it knows http (very well :) ). Recently, I saw PostgREST project - Serve a RESTful API from a Postgres database. I wanted to try that and here I am.

Using the PostgREST, I was able to get it running locally.

Next step is connecting from Workers to PostgREST instance on my server. To do that securely, I turned to Cloudflare Tunnel. It provides a hostname which I can connect to and protects the server too. No need for VPN, or VPC etc.

accessing-postgres-from-cloudflare-workers-1.png

A simple Workers script in Javascript, listens for “fetch” event. Hostname https://cfworkerspostgresdemo.viggy28.dev/is exposed through a Cloudflare tunnel. There is a PostgREST endpoint called /todos.

Workers script

addEventListener("fetch", event => {
  return event.respondWith(handleRequest())
})

async function handleRequest() {
  hostname = "https://cfworkerspostgresdemo.viggy28.dev/"
  const init = {
    headers: {
      "content-type": "text/html;charset=UTF-8",
    }
  }
  const response = await fetch("https://cfworkerspostgresdemo.viggy28.dev/todos", init)
  const results = await gatherResponse(response)
  return new Response(results, init)
}

/**
 * gatherResponse awaits and returns a response body as a string.
 * Use await gatherResponse(..) in an async function to get the response body
 * @param {Response} response
 */
async function gatherResponse(response) {
  const { headers } = response
  const contentType = headers.get("content-type") || ""
  if (contentType.includes("application/json")) {
    return JSON.stringify(await response.json())
  }
  else if (contentType.includes("application/text")) {
    return await response.text()
  }
  else if (contentType.includes("text/html")) {
    return await response.text()
  }
  else {
    return await response.text()
  }
}

Later, I realized I can also access the endpoint even without the worker also by visiting the Tunnel hostname https://cfworkerspostgresdemo.viggy28.dev/

Cloudflare Tunnel Config

tunnel: <replacemewithUUID>
credentials-file: <replacemewithUUID.json>

ingress:
  - hostname: cfworkerspostgresdemo.viggy28.dev
    service: http://localhost:3000
    originRequest:
      connectTimeout: 5s
      proxyType: socks
  - service: http_status:404
  # Catch-all rule, which responds with 404 if traffic doesn't match any of
  # the earlier rules