Reportobello: Build Reports Rapidly

Reportobello is an API for building PDF reports. It's main goals are, in no particular order:

  1. Simplicity: Building a report is as easy as sending JSON to a predefined template
  2. Reliability: Build reports confidently, and diagnose issues quickly
  3. Performance: Reports should be built almost instantly (sub 500ms for most PDFs)

Reportobello uses Typst as the templating engine for making PDFs. Building reports is as easy as:

  1. Uploading your Typst files via our UI, CLI, or API.
  2. Send your data as JSON, get PDF output
  3. Repeat steps 2-3

You can use our API directly, or use one of our SDKs. We currently have support for Python, C#, and JavaScript/Typescript.

Keep reading to see how you can integrate Reportobello into your workflow.

Core Concepts

Here are a few basic concepts that will make using Reportobello a bit easier.

Templates

At the core of Reportobello are templates. Templates are Typst files that are used for creating reports.

For reports to be useful, they need data. When building the report, Reportobello puts your JSON data in a global variable called data:

#import "@rpbl/util:0.0.1": *

Gross earnings: $#data.total

In this example, @rpbl/util is a Typst package which provides the data global variable, along with other util functions. To see all of the functions/variables this package provides, click here. The package is versioned to prevent newer versions from breaking existing functionality.

If you can't (or don't want to) use the @rpbl/util package for whatever reason, you can alternatively load the JSON data directly. Reportobello stores the JSON data for building the report in a file called data.json which your report can load and use:

#let data = json("data.json")

Gross earnings: $#data.total

Reports

Reports are PDFs that are built from templates. Reports also have some metadata like when they were built, who built them, etc.

In the event that a report failed to build, you can use the API to get recently built reports and diagnose why they failed.

Environment Variables

Often times you have data that is shared between lots of reports, for example, your company name, phone number, etc. Environment variables are ways to inject key-value pairs into all your templates.

For example, if you set the key company_name to ACME Corp., you can use that value in your reports like so:

Company Name: #sys.inputs.company_name

Using environment variables has lots of advantages:

  • One source of truth: Updating your values in one place will update them globally
  • Less hard-coding: Using environment variables means less hard coded data in your templates and applications
  • Less bandwidth: Storing these values server-side means that you don't have to re-send them along with your report data

You don't have to use environment variables, but they are there if you need/want them.

Reportobello currently does not support namespaced env vars, meaning all reports will be able to see all env vars. We are working on adding namespaces so that env vars are only scoped to specific reports or groups of reports.

API

This is documentation for how to interface with the Reportobello API directly. If you want to use Reportobello with a programming language like JavaScript or C#, refer to the client libraries page.

Authentication

Almost all API endpoints require an API key to function.

To get an API key, navigate to the login page and login with your GitHub account. We use GitHub to make the login experience quicker, and reduce the likelihood for spam and abuse.

You can also quickly spin-up your own self hosted Reportobello instance.

The reportobello.com site is currently being used for demo purposes, and is periodically reset. It should only be used for testing and should not be used for production!

Once you get an API key, make sure to set the Authorization header like so:

Authorization: Bearer rpbl_YOUR_API_KEY_HERE

All API keys start with rpbl_ to indicate that it is a Reportobello API key.

Endpoints

Refer to the Swager Docs for a list of all the available endpoints, their purpose, and examples.

Rate Limits

By default, API endpoints are rate limited to 5 requests/second. Certain endpoints have stricter rate limiting, while others have no rate limits. Refer to the Swagger documentation to see what the rate limit is for a given endpoint.

Undocumented API endpoints (for example, in the UI) have different rate limits, and are subject to change without notice. Do not rely on them!

For self-hosted instances you can set the REPORTOBELLO_RATE_LIMIT_DISABLED env var to 1 to remove all API rate limits.

Currently there is no way to change rate limits for specific endpoints without modifying the code directly.

Reportobello CLI

If you want to interact with your Reportobello instance using the command line, the Reportobello CLI has you covered.

The Reportobello CLI is written in Python and uses the Python SDK.

Example CLI usage:

$ cat demo.typ
Example Title: #sys.input.TITLE

$ rpbl env set TITLE "Hello World"
$ rpbl push demo.typ
$ rpbl ls -a
╭──────────┬─────────┬─────────────────────────────────╮
│ Name     │ Version │ Template                        │
├──────────┼─────────┼─────────────────────────────────┤
│ demo     │ 1       │ Example Title: #sys.input.TITLE │
╰──────────┴─────────┴─────────────────────────────────╯

Installing

To install the Reportobello CLI, install the reportobello package using pipx:

$ pipx install reportobello

$ rpbl --help

Setup

You must set the REPORTOBELLO_API_KEY environment variable in order to make certain API requests, and if you are using a self-hosted version of Reportobello, you must set REPORTOBELLO_HOST as well.

The CLI will automatically load a .env file if it exists in the current directory. For example, your .env file might look like this:

REPORTOBELLO_API_KEY=rpbl_YOUR_API_KEY_HERE
REPORTOBELLO_HOST=https://example.com

You can also specify these env vars via the command line:

$ export REPORTOBELLO_API_KEY=rpbl_YOUR_API_KEY_HERE
$ export REPORTOBELLO_HOST=https://example.com

$ rpbl --help

Build a Template

Building On Your Reportobello Instance

$ rpbl build TEMPLATE [JSON]

Build the template TEMPLATE on your Reportobello instance (not on your local machine). To specify a JSON file to read and pass to the template, set the JSON argument (defaults to data.json). Use - to read from stdin.

Build a File Locally

$ rpbl build TEMPLATE --local [JSON] [--env KEY=VALUE]

Build the template file TEMPLATE on your local machine. You can pass additional environment variables using the --env flag. This can be repeated.

To specify a JSON file to read and pass to the template, set the JSON argument (defaults to data.json). Use - to read from stdin.

$ rpbl watch TEMPLATE [JSON] [--env KEY=VALUE]

Use the watch command to rebuild whenever TEMPLATE changes.

You can read more about environment variables here.

Publish a Template

$ rpbl push TEMPLATE

Upload TEMPLATE to your Reportobello instance, or if it already exists, create a new version of the template.

Pull a Template

$ rpbl pull TEMPLATE [--version 123]

Pull the latest version of a template TEMPLATE, or pull a specific version using --version or -v.

List Templates

$ rpbl ls [--format=json]

List all templates your Reportobello instance. This will include:

  • Template name
  • Most recent version number
  • Last time template was built (coming soon)
  • Number of builds for this template (coming soon)

By default, a pretty-printed table is displayed. To display JSON instead, use --format=json.

List Template Versions

$ rpbl ls TEMPLATE [-a] [--diff] [--format=json]

List template versions for TEMPLATE. By default, the template content is not shown. To show the template content, use -a (for all).

To show only the differences between the templates, use the --diff option. This implies -a.

By default, a pretty-printed table is displayed. To display JSON instead, use --format=json. Diff output is not shown when using the JSON format.

List Recent Builds For Template

$ rpbl builds ls TEMPLATE [--format=json]

List recent builds for TEMPLATE.

By default, a pretty-printed table is displayed. To display JSON instead, use --format=json.

Environment Variables

List Environment Variables

$ rpbl env
$ rpbl env ls

List all environment variables in your Reportobello instance.

By default, a pretty-printed table is displayed. To display JSON instead, use --format=json.

Set Environment Variables

$ rpbl env set KEY VALUE

Set the environment variable KEY to VALUE. If KEY already exists, override it.

Remove Environment Variables

$ rpbl env rm KEY [KEY...]

Remove the environment variable KEY. Can be repeated. No error is returned when trying to delete a key that doesn't exist.

Client Libraries

Reportobello has SDK support for the following languages:

Feature Support Matrix

Reportobello is constantly adding new features, including upgrades to it's API. While we try to keep the SDKs up to date with the latest changes, they may fall behind when it comes to adding new features.

Here are all the supported API features and their SDK support.

FeatureC#JSPython
Get all templates (GET /api/v1/templates)
Create/update template (POST /api/v1/template/{name})
Get template versions (GET /api/v1/template/{name})
Delete template (DELETE /api/v1/template/{name})
Build template (POST /api/v1/template/{name}/build)
* Specify template version (?version=N)❌ 1❌ 1❌ 1
* Download PDF as blob✅ 2✅ 2
* Download PDF as URL link (?justUrl)
* Build pure PDF 3 (?isPure)
Get recently built reports (GET /api/v1/template/{name}/recent)
* Get reports build before a given date (?before)
Get previously built PDF by filename (GET /api/v1/files/{filename})❌ 4
* Specify download name for PDF (?downloadAs=NAME)N/A
* Automatically download PDF (in browser) (?download)N/A
Get environment variables (GET /api/v1/env)
Set environment variables (POST /api/v1/env)
Delete environment variables (DELETE /api/v1/env)
Convert existing file to template (POST /api/v1/convert/pdf)
Upload data files for templates (POST /api/v1/template/{name}/files)
Delete data files for templates (DELETE /api/v1/template/{name}/file/{filename})
Get/download data files for templates (GET /api/v1/template/{name}/file/{filename})
1

Defaults to latest version

2

PDF is not download directly as a blob, it grabs the URL then re-downloads it as a blob.

3

A "pure" PDF is a PDF built using only the JSON body, and doesn't use environment variables or non-deterministic side-effects like datetime.today(). This means that if the JSON is the same, a cached version can be returned instead.

4

This endpoint is indirectly called when building a report, but the SDK does not allow for re-downloading a PDF with just a URL yet.

C#

This guide shows you how to use Reportobello with C#, specifically for backend applications, and Blazor frontends.

The full source code for this demo can be viewed here.

Reportobello should work with other .NET languages like F# and VB, but has not been tested.

Installing

Via the dotnet CLI:

$ dotnet add package Reportobello
$ dotnet add package Reportobello.Blazor

Or add the following PackageReference directly:

<!-- Replace Version with the latest version -->
<PackageReference Include="Reportobello" Version="1.0.1" />
<PackageReference Include="Reportobello.Blazor" Version="1.0.0" />

The Reportobello package provides the core SDK for the Reportobello API, and is a .NET Standard 2.0 package which can be used with most .NET projects.

The Reportobello.Blazor package provides browser-only utilities like opening PDFs in new tabs, and only supports Blazor. Only install Reportobello.Blazor for Blazor projects!

Configuring Reportobello

Add the following to your Program.cs file to setup dependency injection for Reportobello:

using Reportobello;
using Reportobello.Blazor;

// ...

builder.Services
    // Reportobello API
    .AddSingleton(
        new ReportobelloApi(
            builder.Configuration.GetValue<string>("Reportobello:ApiKey"),
            builder.Configuration.GetValue<string>("Reportobello:Host")
        )
    )
    // Blazor Utils
    .AddScoped<ReportobelloUtil>();

Then, in your appsettings.json, add the following:

{
  "Reportobello": {
    "ApiKey": "rpbl_YOUR_API_KEY_HERE",
    "Host": "https://reportobello.com"
  }
}

If you are using a self-hosted version of Reportobello, change the Host field to the URL for your local instance.

Now you will be able to inject Reportobello or ReportobelloUtil into your code!

Injecting Reportobello

To use Reportobello in you code, you need to inject 2 services:

  • ReportobelloApi: The API instance for building the actual reports
  • ReportobelloUtil: A helper class for displaying/handling PDFs in the browser

Add the following code to your Blazor component:

[Inject]
public ReportobelloApi ReportobelloApi { get; set; } = default!;
[Inject]
public ReportobelloUtil Util { get; set; } = default!;

Note: If you aren't using Blazor, inject the services using your typical dependency injection system. As mentioned previously, ReportobelloUtil can only be used in Blazor projects, while ReportobelloApi can be used with any .NET Standard 2.0 compatible project.

Creating Templates

Before you can build a report, you need to upload it's template file. You only need to upload a template when you first create it or when you modify it. You can upload it using the user interface, or by using a code-first approach, which is discussed below.

Reportobello uses Typst as it's templating language. Read the Typst docs for more info on how to make templates with Typst.

Weakly Typed Templates

If you don't want to create a record or class for your template data, you can specify the template name and contents directly:

await ReportobelloApi.UploadTemplate("quarterly_report", "// Template contents here");

While weakly typed templates are easier in to start out with, as your template becomes more complex, strong typing will make building reports easier and less error prone.

Strongly Typed Templates

To strongly type your template data, create a record or class that represents the structure of your template data:

record QuarterlyReport(int quarter, decimal total);

Then give a name to your template via the TemplateName attribute:

[TemplateName("quarterly_report")]
record QuarterlyReport(int quarter, decimal total);

This gives you enough to upload the template:

string templateContent = "// Template content here";

await ReportobelloApi.UploadTemplate<QuarterlyReport>(templateContent);

Optionally, you can specify the template file in the record itself. If you already have a .typ template file in repository, add the TemplateFile attribute:

[TemplateName("quarterly_report")]
[TemplateFile("reports/quarterly_report.typ")]
record QuarterlyReport(int quarter, decimal total);

You can also specify the template contents directly:

[TemplateName("quarterly_report")]
[TemplateContent("""

// Template content here

""")]
record QuarterlyReport(int quarter, decimal total);

Then you can upload the template without specifying the content:

await ReportobelloApi.UploadTemplate<QuarterlyReport>();

Building Reports

To build a report, use the template we created above to build the report:

private async Task GeneratePdf()
{
    // Build the report data
    var report = new QuarterlyReport(quarter: 1, total: 123_456_789);

    // Call the API, get resulting PDF url
    var url = await ReportobelloApi.RunReport(report);
}

If you are using weakly-typed templates, you will need to specify the name of the template:

var url = await ReportobelloApi.RunReport("quarterly_report", report);

You don't have to use template objects with RunReport, any JSON serializable object will do:

var report = new {quarter: 1, total: 123_456_789};

var url = await ReportobelloApi.RunReport("quarterly_report", report);

Displaying the PDF

The rest of this page is for Blazor projects that want to display/download PDFs in a browser.

Download Report PDF

Download the PDF directly, opening it in a new tab.

Function signature:

public async Task Download(Uri url, string downloadAs="report.pdf")
public async Task Download(string url, string downloadAs="report.pdf")

Arguments:

  • url: The PDF URL to download
  • downloadAs: Changes the default filename of the PDF when downloaded via the browser

Examples:

await Util.Download(url);
await Util.Download(url, downloadAs: "Earnings Report.pdf");

Open Report in New Tab

Opens the PDF in a new tab.

Function signature:

public async Task OpenInNewTab(Uri url, string? downloadAs=null, bool download=false)
public async Task OpenInNewTab(string url, string? downloadAs=null, bool download=false)

Arguments:

  • url: The PDF URL to download
  • downloadAs: Changes the default filename of the PDF when downloaded via the browser
  • download: When true, download the file in addition to opening it in a new tab

Examples:

await Util.OpenInNewTab(url);
await Util.OpenInNewTab(url, downloadAs: "Earnings Report.pdf");

// Equivalent to Download(url, name);
await Util.OpenInNewTab(url, downloadAs: "Earnings Report.pdf", download: true);

Open PDF in Existing Iframe

Open the PDF in an existing <iframe>.

Function signature:

public async Task OpenInIframe(Uri url, object elementRef, string? downloadAs=null)
public async Task OpenInIframe(string url, object elementRef, string? downloadAs=null)

Arguments:

  • url: The PDF URL to download
  • elementRef: A string CSS selector for the iframe, or an ElementReference to an iframe
  • downloadAs: Changes the default filename of the PDF when downloaded via the browser

Examples:

await Util.OpenInIframe(url, "#iframe");

// or, using `ElementReference`

public ElementReference Iframe { get; set; } = default!;

await Util.OpenInIframe(url, Iframe);

JavaScript/TypeScript

Installing

To install, run:

$ npm i reportobello

Configuring Reportobello

To use Reportobello, create a new API instance using your API key:

import { Reportobello } from "reportobello";

const api = new Reportobello({apiKey: "rpbl_YOUR_API_KEY_HERE"});

Never hard code API keys! This is only an example. In Node.js use process.env.XYZ to read sensitive data from environment variables. If you are using Reportobello from a browser, your API key will be available to anyone with the source code. We are working on fine-grained token permissions, which would allow you to expose read/write only API keys.

If you are using a self-hosted version of Reportobello, make sure to set the host option:

const api = new Reportobello({apiKey: "rpbl_YOUR_API_KEY_HERE", host: "https://example.com"});

Creating Templates

Before you can build a report, you need to upload it's template file:

const template = `
#import "@rpbl/util:0.0.1": *

= Q#data.quarter Earnings Report

Generated: #datetime.today().display()

Earnings: $#data.earnings
`;

await api.createOrUpdateTemplate("quarterly_report", template);

Refer to the Typst docs to learn how to create Typst templates.

Building Reports

Once you have a template you can start building reports!

Use the runReport function to build a report:

const url: URL = api.runReport(name, data);

This will return a URL object which you can use to display, render, or download the PDF.

All the examples below will use the following globals:

const name = "quarterly_report";
const data = {"quarter": 1, "total": "123,456,678.00"};

Download Report PDF

Download the PDF directly, opening it in a new tab.

Function signature:

download(url: URL | string, downloadAs: string="report.pdf"): void;

Arguments:

  • downloadAs: Changes the default filename of the PDF when downloaded via the browser.

Examples:

api.runReport(name, data).then(download);

// or

api.runReport(name, data).then(x => download(x));
api.runReport(name, data).then(x => download(x, "customName.pdf"));

// or

const url = await api.runReport(name, data);
download(url);
download(url, "customName.pdf");

Open Report in New Tab

Use the openInNewTab() function to open the PDF in a new tab.

Function signature:

openInNewTab(url: URL | string, downloadAs?: string, download?: boolean=false): void;

Arguments:

  • downloadAs: Changes the default filename of the PDF when downloaded via the browser.
  • download: Set to true to download the file in addition to opening it in a new tab.

Examples:

api.runReport(name, data).then(openInNewTab);

// or

api.runReport(name, data).then(x => openInNewTab(x));

// or

const url = await api.runReport(name, data);
openInNewTab(url);

Open PDF in Existing Iframe

Use this to open the PDF in an existing iframe.

Function signature:

openInIframe(url: URL | string, ref: string, downloadAs?: string): void;

Arguments:

  • ref: The CSS selector for the iframe element
  • downloadAs: Set the name of the PDF when downloaded through the iframe

Examples:

api.runReport(name, data).then(x => openInIframe(x, "#id-of-iframe"));

// or

const url = api.runReport(name, data);
openInIframe(url, "#id-of-iframe");

PDF Building Options

Pure PDFs

A "pure" PDF is a PDF built using only the JSON body, and doesn't use environment variables or non-deterministic side-effects like datetime.today(). This means that if the JSON is the same, a cached version can be returned instead.

To use a cached PDF if one exists (or build one like normal if it doesnt exist), set the pure option:

const url = await api.runReport(name, data, {pure: true})

Uploading Data Files

If you have a template that requires custom fonts, images, or other data files (JSON, txt, csv, etc), you can upload these files using the uploadDataFiles() method:

const files = document.querySelector("input[type=file]").files

// Using `FileList` object (from `<input type="file">` elements)
await api.uploadDataFiles(name, files);

// Using array of `File` objects
await api.uploadDataFiles(name, [files[0]]);

// Using array of manually built file objects
await api.uploadDataFiles(name, [
  {
    name: "file.txt",
    blob: new Blob(["Hello world"], {type: "text/plain"}),
  }
]);

After uploading these files you will be able to use the files in your template:

= Example Image

#image("img.jpg")

Note: Directories are stripped from filename when uploading. For example, if you upload images/img.jpg, the file will be uploaded as img.jpg.

Deleting Templates

When you delete a template it will "soft-delete" it, meaning you will not be able to access it, but it will still exist in the system for billing purposes.

When you delete a template you will not be able to access report metadata for reports built for that template. You will still be able to download PDFs if you have the direct URL.

await api.deleteTemplate("quarterly_report");

Get Recently Built Reports

To get a list of all the reports that have been built for a given template, use the following:

const reports = await api.getRecentReports("quarterly_report");

Note: The API currently does not allow for sorting, searching, or pagination, all reports will be returned. In the future pagination might be added, so do not rely on all results being returned.

Environment Variables

You can read more about environment variables in Reportobello here.

Creating/Updating Environment Variables

await api.updateEnvVars({
  companyName: "ACME Corp.",
  companyPhoneNumber: "123-456-7890",
});

Delete Environment Variables

await api.deleteEnvVars(["companyName", "companyPhoneNumber"]);

Using with TypeScript

If you are using TypeScript, you can use the generic version of runReport() to type-check JSON data before it gets sent to Reportobello:

interface QuarterlyReport {
  // ...
}

api.runReport<QuarterlyReport>(name, data).then(download);

Python

Installing

$ pip install reportobello

Configuring Reportobello

To start using Reportobello, create a new API instance:

from reportobello import ReportobelloApi

# Automatically read the REPORTOBELLO_API_KEY and REPORTOBELLO_HOST env var
api = ReportobelloApi()

# Explicitly pass API key
api = ReportobelloApi("rpbl_YOUR_API_KEY_HERE")

Never hard code API keys! This is only an example. Use os.getenv() to read API keys from environment variables.

If you are using a self-hosted version of Reportobello, make sure to set the host argument:

api = ReportobelloApi(host="https://example.com")

Creating Templates

Before you can build a report, you need to upload it's template file. You only need to upload a template when you first create it or when you modify it. You can upload it using the user interface, or by using a code-first approach, which is discussed below.

from dataclasses import dataclass

from reportobello import Template


@dataclass
class QuarterlyReport(Template):
    # The name to use for this template
    name = "quarterly_report"

    # Path to Typst template file
    file = "path/to/report.typ"

    # Template data
    quarter: int
    earnings: float

# Upload template via API
await api.create_or_update_template(template)

The path/to/report.typ file is a Typst template file for building the report. In this example, the report.typ file will use the following contents:

#import "@rpbl/util:0.0.1": *

= Q#data.quarter Earnings Report

Generated: #datetime.today().display()

Earnings: #data.earnings

Typst is a powerful templating language which supports rich typesetting, variables, conditions, functions, and much much more. Refer to the Typst docs to learn more about Typst templates.

If you would rather store the template in the class directly you can set the content property instead:

@dataclass
class QuarterlyReport(Template):
    # ...

    content = """
#import "@rpbl/util:0.0.1": *

= Q#data.quarter Earnings Report

Generated: #datetime.today().display()

Earnings: #data.earnings
"""

  # ...

Building Reports

Once you have a template you can start building reports! The QuarterlyReport template we created can be passed to most template= arguments, and contains all the metadata needed for dealing with templates. To build a template, run the following:

# Create a new template instance
template = QuarterlyReport(quarter=1, earnings=123_456)

# Build the report
pdf = await api.build_template(template)

In some cases though, it might be desirable to separate the template name from the template data, for instance, if you are not using dataclasses. In that case, you can pass the template name, and the template data as a dictionary or dataclass:

pdf = await api.build_template("quarterly_report", {"quarter": 1, "earnings": 123_456})

# or, if you want to use a Template object, but not the data:
pdf = await api.build_template(QuarterlyReport(), {"quarter": 1, "earnings": 123_456})

The rest of the code examples below will start with the following boilerplate:

template = QuarterlyReport(quarter=1, earnings=123_456)

pdf = await api.build_template(template)

Download PDF To Disk

To build a report and download the file directly use the following:

await pdf.save_to("output.pdf")

# or, using Path:
await pdf.save_to(Path("output.pdf"))

Download PDF In-Memory

To build a report and save the PDF blob directly to a variable, use the following:

blob = await pdf.as_blob()

Just Get URL

If you only want to get the URL of the built report, use the following:

url = pdf.url

Pure PDFs

A "pure" PDF is a PDF built using only the JSON body, and doesn't use environment variables or non-deterministic side-effects like datetime.today(). This means that if the JSON is the same, a cached version can be returned instead.

To use a cached PDF if one exists (or build one like normal if it doesnt exist), set the is_pure keyword arg:

pdf = await api.build_template(template, is_pure=True)

Deleting Templates

When you delete a template it will be "soft-deleted", meaning you will not be able to access it, but it will still exist in the system for billing purposes.

When you delete a template you will not be able to access report metadata for reports built for that template, though you will still be able to download PDFs if you have the direct URL.

await api.delete_template("quarterly_report")

# or, using existing template instance
await api.delete_template(template)

Uploading Data Files

If you have a template that requires custom fonts, images, or other data files (JSON, txt, csv, etc), you can upload these files using the upload_data_files() method:

# You can upload files via Path or str objects
files = [Path("img1.jpg"), "img2.jpg"]

await api.upload_data_files(template, *files)

After uploading these files you will be able to use the files in your template:

= Example Image

#image("img.jpg")

Note: Directories are stripped from filename when uploading. For example, if you upload images/img.jpg, the file will be uploaded as img.jpg.

Get Recent Builds for a Template

To get a list of all the reports that have been built for a given template, use one of the following:

reports = await api.get_recent_builds("quarterly_report")

# or, using existing template instance
reports = await api.get_recent_builds(template)

To get reports built before a given time, use the before keyword:

reports = await api.get_recent_builds(template, before=datetime.now(tz=utc))

Note that the datetime object passed to before must be a UTC datetime!

Note that the API/SDK currently does not support filtering, pages, or page size, it only supports the before keyword.

Environment Variables

You can read more about environment variables in Reportobello here.

Creating/Updating Environment Variables

await api.update_env_vars({
  "company_name": "ACME Corp.",
  "company_phone_number": "123-456-7890",
})

Delete Environment Variables

await api.delete_env_vars(["company_name", "company_phone_number"])

Self Hosting

This page is a breakdown of how to self-host your own Reportobello instance.

Local Testing

To experiment with Reportobello locally, run the following Docker command:

$ docker run -it \
    --name reportobello \
    -p 8000:8000 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /tmp:/tmp \
    ghcr.io/reportobello/server

...

reportobello-1  |
reportobello-1  | "admin" API key: rpbl_8dCCwVD4kMtmk_s3qODaiaa9_6MVyHXnhTODuohdcZI
reportobello-1  |
reportobello-1  | 2024-10-20T01:22:27.952 INFO:     Started server process [1]
reportobello-1  | 2024-10-20T01:22:27.952 INFO:     Waiting for application startup.
reportobello-1  | 2024-10-20T01:22:27.952 INFO:     Application startup complete.
reportobello-1  | 2024-10-20T01:22:27.952 INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

To start using Reportobello:

When you're done, type CTRL+C to stop the server. Your data will be stored in the reportobello container, and will be kept across restarts since the --rm flag is not used. To start, stop, or destroy you Reportobello instance, run the following commands:

# Start a previously stopped instance
$ docker start reportobello

# Stop the currently running instance
$ docker stop reportobello

# Destroy the instance
$ docker rm reportobello

Production

To use Reportobello in a production environment, you will probably want to enable/disable some environment variables:

General

  • REPORTOBELLO_DOMAIN: The domain that the Reportobello instance is hosted from. Not setting this can cause CSRF issues when generating PDF URLs.
  • REPORTOBELLO_RATE_LIMIT_DISABLED: By default, API requests in Reportobello are rate-limited. To disable rate-limits, set this to 1. Note that this is different than monthly rate limits, which do not apply to the admin API key.
  • REPORTOBELLO_ADMIN_API_KEY: Hard-code the admin API key (by default a key is auto-generated once on initial boot). If provided, it must match the following regex: ^rpbl_[0-9A-Za-z_-]{43}$

To securely create a random, valid API key, run one of the following:

# If you don't have a running instance
$ docker run --rm --entrypoint mint_api_key ghcr.io/reportobello/server

# If you do have a running instance
$ docker compose exec reportobello mint_api_key

GitHub

Note: This probably should not be enabled, as it allows anyone with a GitHub account to create an account on your Reportobello instance.

  • REPORTOBELLO_GITHUB_OAUTH_CLIENT_ID: If you want to enable GitHub OAuth support, set your OAuth client ID here.
  • REPORTOBELLO_GITHUB_OAUTH_CLIENT_SECRET: Same as above, but for the OAuth client secret.

Jaeger/OTEL

Note: This should probably not be set unless you need to debug Reportobello, or want to ingest it's telemetry data.

Backups

To backup Reportobello, copy the data folder to safe location:

$ docker cp reportobello:/app/data /path/to/dir/rpbl_backup

To restore from a backup, create a new Reportobello instance and point it to the backup location:

$ docker run -it \
    --name reportobello-restored \
    -p 8000:8000 \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /tmp:/tmp \
    -v /path/to/dir/rpbl_backup:/app/data \
    ghcr.io/reportobello/server

Building Templates

Reportobello uses Typst as it's templating engine. To learn more about Typst and how to use it, read their docs.

In addition to the existing Typst features, Reportobello adds some additional features to make building reports easier. To learn more about those, go to the next chapter.

The @rpbl/util Package

Current package version: 0.0.1

The @rpbl/util package is used by Reportobello to inject global variables and other helper functions which aren't provided natively in Typst. Examples include ISO 8601 datetime parsing and automatically loading JSON data in the template.

Globals

data

This global variable stores the JSON payload passed to the report via the API (or CLI).

Example Usage:

{
  "invoice": {
    "number": 1234,
    "rows": [
      {
        "item": "Widget",
        "cost": "$1"
      }
    ]
  }
}
#import "@rpbl/util:0.0.1": *

Invoice \#: #data.invoice.number

Invoice Row 1: #data.invoice.rows.at(0)

This is the full JSON payload: #data

Functions

iso8601

This function parses a string in ISO 8601 datetime format and returns a datetime object.

Note: Typst does not support timezones or sub-second percision, so those values are stripped before parsing. This behaviour might change in the future.

Example Usage:

#import "@rpbl/util:0.0.1": *

#iso8601("2024-11-11T19:51:41.711304+00:00")
#iso8601("2024-11-11T19:51:41.711304")
#iso8601("2024-11-11T19:51:41")
#iso8601("2024-11-11")