# Cache API

import Code from '~/components/Code/Code.astro'
import Tabs from '~/components/tabs/Tabs'

The Cache API allows you to control reading and writing from [Cache](https://www.azion.com/en/products/edge-cache/) through Functions.

#### Request headers

| Header                | Description                                                      |
|-----------------------|------------------------------------------------------------------|
| `x-storage-operation` | cache-storage ops (`open`, `has`, `delete`)                      |
| `x-cache-operation`   | cache ops (`match`, `put`, `delete`, `none`, `all`)              |
| `x-storage-name`      | cache-storage name (optional, default: `"my-cache"`)             |

<Tabs client:visible>
    <Fragment slot="tab.esmodules">ES Modules Syntax</Fragment>
    <Fragment slot="tab.moduleworker">Module Worker Syntax</Fragment>

<Fragment slot="panel.esmodules">

<Code lang="javascript" code={`
export async function fetch(request, env, ctx) {

  const responseHeaders = { "content-type": "text/plain" };

  try {

    const cacheName =
      request.headers.get("x-cache-name")    // Prioritize header
      ?? env.CACHE_NAME                      // binding fallback
      ?? "default";                          // final fallback

    const cache = await caches.open(cacheName);

    if (request.headers.get("x-clear-cache")) {
      await cache.delete(request);
      return new Response(null, { headers: responseHeaders, status: 205 });
    }

    
    const cachedResponse = await cache.match(request);
    if (cachedResponse) return cachedResponse;

   
    const originURL = "https:/xxxxxxxx.map.azionedge.net";
    const fetchResponse = await fetch(originURL);

    ctx.waitUntil(cache.put(request, fetchResponse.clone()));

    return new Response(
      "I couldn't load cache, because I'm a teapot!",
      { headers: responseHeaders, status: 418 }
    );
  } catch (err) {
    console.error(err);
    return new Response(err.message, { headers: responseHeaders, status: 500 });
  }
}`} />


</Fragment>

<Fragment slot="panel.moduleworker">

<Code lang="javascript" code={`

function generateResponse(message, status) {
  return new Response(message, {
    headers: { "content-type": "text/plain" },
    status,
  });
}

async function runCacheOperation(cache, op, request) {
  switch (op) {
    case "none":
      return generateResponse("success in cache open!", 200);

    case "match": {
      console.log("[INFO] 'match' operation");
      const cached = await cache.match(request);
      if (cached) {
        console.log("[INFO] Cache hit for: " + request.url);
        return cached;
      }
      console.log("[INFO] No content cached");
      return generateResponse("No content cached", 404);
    }

    case "put": {
      console.log("[INFO] 'put' operation");
      const resp = generateResponse("my content", 200);
      await cache.put(request, resp.clone());
      return resp;
    }

    case "delete":
      console.log("[INFO] 'delete' operation");
      await cache.delete(request);
      return generateResponse("OK", 200);

    case "all": {
      console.log("[INFO] 'all' operations (put -> match -> delete)");
      const resp = generateResponse("my content", 200);
      await cache.put(request, resp.clone());
      await cache.match(request);
      await cache.delete(request);
      return generateResponse("all ops ok", 200);
    }

    default:
      console.log("[INFO] invalid cache operation");
      return generateResponse("Invalid cache operation", 400);
  }
}

export async function fetch(request, env, ctx) {
  const storageOp = request.headers.get("x-storage-operation");
  const cacheOp   = request.headers.get("x-cache-operation");
  const storageName =
    request.headers.get("x-storage-name") ||
    env.DEFAULT_CACHE_NAME ||           // binding opcional
    "my-cache";

  try {
    switch (storageOp) {
      /* ---------- cacheStorage.open ---------- */
      case "open": {
        console.log("[INFO] cache storage 'open' operation");
        const cache = await caches.open(storageName);
        console.log("[INFO] storage cache '" + storageName + "' opened");
        return runCacheOperation(cache, cacheOp, request);
      }

      /* ---------- cacheStorage.has ---------- */
      case "has": {
        console.log("[INFO] cache storage 'has' operation");
        const exists = await caches.has(storageName);
        const msg = exists
          ? "Cache storage '" + storageName + "' exists."
          : "Cache storage '" + storageName + "' does NOT exist.";
        console.log("[INFO] " + msg);
        return generateResponse(msg, 200);
      }

      /* ---------- cacheStorage.delete ---------- */
      case "delete": {
        console.log("[INFO] cache storage 'delete' operation");
        const deleted = await caches.delete(storageName);
        const msg = deleted
          ? "Success deleting cache storage '" + storageName + "'."
          : "Cache storage '" + storageName + "' doesn't exist.";
        console.log("[INFO] " + msg);
        return generateResponse(msg, 200);
      }

      /* ---------- invalid op ---------- */
      default:
        console.log("[INFO] invalid cache storage operation");
        return generateResponse("Invalid cache storage operation", 400);
    }
  } catch (err) {
    console.error("[ERROR]", err);
    return generateResponse(err.message, 500);
  }
}
`} />

</Fragment>

</Tabs>