BonnardBonnard0.3.14

Browser / CDN Quickstart

Load the Bonnard SDK via a `<script>` tag and query your semantic layer from any HTML page.

Setup

Add the SDK script tag to your HTML. It exposes window.Bonnard.

<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk/dist/bonnard.iife.js"></script>

Alternative CDN:

<script src="https://unpkg.com/@bonnard/sdk/dist/bonnard.iife.js"></script>

Pin a specific version:

<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk@latest/dist/bonnard.iife.js"></script>

First query

<script src="https://cdn.jsdelivr.net/npm/@bonnard/sdk/dist/bonnard.iife.js"></script>
<script>
  const bon = Bonnard.createClient({
    apiKey: "bon_pk_YOUR_KEY_HERE",
  });

  (async () => {
    const { data } = await bon.query({
      measures: ["orders.revenue", "orders.count"],
      dimensions: ["orders.city"],
      orderBy: { "orders.revenue": "desc" },
      limit: 10,
    });

    console.log(data);
    // [{ "orders.revenue": 125000, "orders.count": 340, "orders.city": "Berlin" }, ...]
  })();
</script>

Note: the IIFE bundle uses a regular <script> tag (not type="module"), so top-level await is not available. Wrap async code in an IIFE or use .then().

Async patterns

<script>
  (async () => {
    const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });
    const { data } = await bon.query({ measures: ["orders.revenue"] });
    document.getElementById("revenue").textContent = data[0]["orders.revenue"];
  })();
</script>

Promise chain

<script>
  const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });

  bon
    .query({ measures: ["orders.revenue"] })
    .then(({ data }) => {
      document.getElementById("revenue").textContent = data[0]["orders.revenue"];
    })
    .catch((err) => {
      console.error("Query failed:", err.message);
    });
</script>

Parallel queries

<script>
  (async () => {
    const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });

    const [kpis, byCity] = await Promise.all([
      bon.query({ measures: ["orders.revenue", "orders.count"] }),
      bon.query({
        measures: ["orders.revenue"],
        dimensions: ["orders.city"],
        orderBy: { "orders.revenue": "desc" },
      }),
    ]);

    // Render KPIs
    document.getElementById("revenue").textContent = kpis.data[0]["orders.revenue"];
    document.getElementById("count").textContent = kpis.data[0]["orders.count"];

    // Render chart with byCity.data...
  })();
</script>

Error handling

Errors from the API are instances of Bonnard.BonnardError, which includes the HTTP status code:

<script>
  (async () => {
    const bon = Bonnard.createClient({ apiKey: "bon_pk_..." });

    try {
      const { data } = await bon.query({
        measures: ["orders.revenue"],
      });
      renderDashboard(data);
    } catch (err) {
      if (err instanceof Bonnard.BonnardError) {
        // API error — check status code
        document.getElementById("error").textContent = `Error ${err.statusCode}: ${err.message}`;
      } else {
        // Network error — no response received
        document.getElementById("error").textContent = "Network error";
      }
      document.getElementById("error").style.display = "block";
    }
  })();
</script>

Common errors:

  • statusCode: 401 — invalid or expired API key
  • statusCode: 400 — invalid measure/dimension names or query structure
  • TypeError (not BonnardError) — network failure, CORS, or connectivity issue

See Errors for the full error reference and retry patterns.

Custom base URL

By default the SDK points to https://app.bonnard.dev. Override for self-hosted or preview deployments:

<script>
  const bon = Bonnard.createClient({
    apiKey: "bon_pk_...",
    baseUrl: "https://your-deployment.vercel.app",
  });
</script>

What's on window.Bonnard

The IIFE bundle exposes two exports:

ExportPurpose
Bonnard.createClient(config)Create an SDK client instance
Bonnard.toCubeQuery(options)Convert QueryOptions to a Cube-native query object (useful for debugging)
Bonnard.BonnardErrorError class with statusCode and retryable — use with instanceof for error handling

Field naming

All field names must be fully qualified with the view name:

// Correct
bon.query({ measures: ["orders.revenue"], dimensions: ["orders.city"] });

// Wrong — will fail
bon.query({ measures: ["revenue"], dimensions: ["city"] });

Discovering available fields

Use explore() to discover what views, measures, and dimensions are available:

const meta = await bon.explore();
for (const view of meta.cubes) {
  console.log(view.name);
  console.log(
    "  Measures:",
    view.measures.map((m) => m.name),
  );
  console.log(
    "  Dimensions:",
    view.dimensions.map((d) => d.name),
  );
}

Next steps

On this page