Hanami LogoHanami

Getting Started

Hanami is a specialized scripting language designed to help you create beautiful reports using dynamic data.

Before you begin, you'll need to download and install the Hanami application and CLI. Visit our downloads page to get the latest version for your operating system.

You can also download an example report here.
Upload the .json file to your Hanami editor and build it to see the results.

Basic Syntax

Hanami uses a clean, intuitive syntax that's easy to learn.

Variables

Variables are declared using the let keyword:

Variable Declaration

Declare variables with the let keyword:

let global_endpoint = "api.com"
let httpheaders = { a: b, c: d }

Document Structure

Every Hanami report starts with a document declaration, which serves as the entry point for your report.

Every Hanami report starts with a document declaration, which serves as the entry point for your report (similar to a main() function in other languages):

Document Declaration

Basic document structure with metadata:

document main {
    author "John Doe"
    date "2025-01-01"
    
    Content goes here
}

The document can include metadata such as the author and date, followed by the content of your report.

Sections

Sections are the building blocks of a Hanami report.

Sections are the building blocks of a Hanami report. They can contain various elements such as titles, subtitles, tables, charts, and lists:

Section Definition

Create sections with various content elements:

let testsection = section {
    title "New Title"
    subtitle "Test Subtitle"
    table {
        headers ["a", "b", "c"]
        rows [
            ["a", "b", "c"],
            ["d", "e", "f"]
        ]
    }
}

Sections can be defined separately and then included in the document using the spread operator (...):

Using Sections in Documents

Include sections in your document:

document main {
    author "John Doe"
    date "2025-01-01"
    
    ...testsection    
}

Tables

Tables are a common way to present data in Hanami.

Tables are a common way to present data in Hanami. They consist of headers and rows:

Table Definition

Create tables with headers and rows:

let secondsection = section {
    title "Second Section"
    subtitle "Test Subtitle"
    table {
        headers ["a", "b", "c"]
        rows [
            ["a", "b", "c"],
            ["d", "e", "f"],
            ["g", "h", "i"],
            ["j", "k", "l"],
            ["m", "n", "o"]
        ]
    }
}

Tables can be included in sections and will be rendered with proper formatting in the final report.

Charts

Hanami supports creating charts from data.

Hanami supports creating charts from data. You can define chart data and then use it in a section:

Chart Creation

Create bar and pie charts:

let barChart = section {
    title "Sales by Quarter"
    chart {
        type "bar"
        labels ["Q1", "Q2", "Q3", "Q4"]
        data [10000, 15000, 12000, 18000]
    }
}

let pieChart = section {
    title "Revenue Distribution"
    chart {
        type "pie"
        labels ["Product A", "Product B", "Product C"]
        data [45, 30, 25]
    }
}

document main {
    ...barChart
    ...pieChart
}

Charts can be customized with different types, labels, and data values. Hanami supports various chart types including bar, line, pie, and more.

Images

Hanami provides several ways to include images in your reports.

Hanami provides several ways to include images in your reports:

Image Functions

Different ways to embed images:

coverimage("https://picsum.photos/id/237/200/300", 100, 200)

embeddedimage("local", "https://picsum.photos/id/237/200/300", 100, 200)

embeddedimage("http", "https://picsum.photos/id/237/200/300", 100, 200)

The coverimage function adds a cover image to your report, while embeddedimage embeds an image within the report content. Both functions take parameters for the image source and dimensions.

Lists

Bullet lists can be created within sections.

Bullet lists can be created within sections:

Bullet Lists

Create bullet lists in sections:

let bulletlist = section {
    title "Bullet List"
    subtitle "Test Subtitle"
    bullet_list [
        "Item 1",
        "Item 2",
        "Item 3"
    ]
}

The bullet_list function takes an array of strings and renders them as a bulleted list in the report.

Variables

Variables in Hanami can store various types of data.

Variables in Hanami can store various types of data, including strings, numbers, objects, and more complex data structures:

Variable Types

Different types of variables:

let global_endpoint = "api.com"

let httpheaders = { a: b, c: d }

let testsection = section {
    title "New Title"
    subtitle "Test Subtitle"
}

Variables can be used throughout your Hanami script to store and reuse data, sections, and other elements.

Pipelines

Pipelines in Hanami allow you to process data and return a result.

Pipelines in Hanami allow you to process data and return a result:

Pipeline Processing

Process data with pipelines:

let processedData = pipeline {
    let sales = [
        { product: "A", amount: 100 },
        { product: "B", amount: 200 },
        { product: "C", amount: 300 }
    ]
    
    let total = sales[0].amount + sales[1].amount + sales[2].amount
    
    let average = total / 3
    
    return {
        data: sales,
        total: total,
        average: average,
        highest: sales[2].amount,
        lowest: sales[0].amount
    }
}

let dataSection = section {
    title "Sales Analysis"
    body "Total Sales: {processedData.total}"
    body "Average Sale: {processedData.average}"
    body "Highest Sale: {processedData.highest}"
}

Pipelines can contain variable declarations, calculations, and must end with a return statement that specifies the data to be returned. They are useful for data transformation and preparation before visualization.

Expressions & Variables

Hanami supports various types of expressions and variable assignments for building dynamic reports.

Integer Expressions

Basic integer literals and arithmetic operations:

Integer Expressions

Basic integer literals and arithmetic operations:

// Simple integers
2
8

// Arithmetic with precedence
2 + 2        // Result: 4
(2 + 2) * 2  // Result: 8

Variable Assignment

Use the let keyword to assign values to variables:

let a = 5
a  // Returns: 5

let variable = section {
    title "value"
    subtitle "subtitle"
    body "value"
}

Hash Objects & Indexing

Create and access hash objects (key-value pairs):

// Creating hash objects
let hash = { "foo": 5 }
hash["foo"]  // Returns: 5

// Complex hash with arrays
let data = {
    "a": [1, 2, 3],
    "b": "test string"
}
data["b"]  // Returns: "test string"

String Interpolation

Embed variables within strings using double curly braces:

let value = "https://google.com"
body "the value is: {{value}} and we like it like this."

JSON Handling

Hanami provides powerful JSON processing capabilities for working with API responses and data files.

Parse JSON from HTTP

Parse JSON data from HTTP API calls:

let response = http("https://jsonplaceholder.typicode.com/posts/1", {
    "Accept": "application/json"
})
let parsed = json(response["body"])

Read JSON from File

Load and parse JSON data from local files:

let jsondata = jsonfromfile("./testdata/complicated_json.json")
pretty(jsondata)  // Pretty-print the JSON structure

Working with Complex JSON

Handle nested JSON structures and extract specific fields:

// Complex nested JSON
let testJson = { "a": { "b": { "c": "d" } } }
pretty(testJson)

// Extract specific fields from arrays
let response = http("https://jsonplaceholder.typicode.com/posts", {
    "Accept": "application/json"
})
let parsed = json(response["body"])
let value = parsed[0]  // Get first item
pretty(value)

Data Processing

Transform and filter data for use in reports and visualizations.

Filtering Data with filterkeep

Keep only specific fields from your data:

// Filter HTTP response data
let response = http("https://jsonplaceholder.typicode.com/posts/1", {
    "Accept": "application/json"
})
let parsed = json(response["body"])
filterkeep(parsed, ["userId", "id", "title", "body"])
 
// Filter array data
let keystokeep = ["a", "b"]
let originaldata = [
    { "a": 1, "b": 2, "c": 3 },
    { "a": 4, "b": 5, "c": 6 }
]
filterkeep(originaldata, keystokeep)

Converting Data to Tables

Transform filtered data into table format for display:

// Convert filtered data to table
let response = http("https://jsonplaceholder.typicode.com/posts", {
    "Accept": "application/json"
})
let parsed = json(response["body"])
_table(parsed[0])  // Convert first item to table
 
// Filter and convert to table
let keystokeep = ["a", "b"]
let originaldata = [
    { "a": 1, "b": 2, "c": 3 },
    { "a": 4, "b": 5, "c": 6 }
]
_table(filterkeep(originaldata, keystokeep))

File I/O

Read data from various file formats including CSV, Excel, and JSON.

CSV Files

Load CSV data directly into table format:

csv("testdata/test.csv")

Excel Files

Read specific sheets from Excel workbooks:

excel("testdata/financial.xlsx", "Sheet1")

JSON Files

Load and parse JSON files:

let jsondata = jsonfromfile("./testdata/complicated_json.json")
pretty(jsondata)

Imports & Modules

Hanami supports modular programming through imports, allowing you to use built-in modules and custom libraries.

Built-in Modules

Import and use built-in modules:

// Math module
import "math"
math.add(1, 2)  // Returns: 3

// Custom test module
import "test"
test.helloworld("value")

DataFrame Module

The dataframe module provides advanced data manipulation capabilities:

import "dataframe"

let d = pipeline {
    let response = http("https://jsonplaceholder.typicode.com/posts", {
        "Accept": "application/json"
    })
    let parsed = json(response["body"])
    let df = dataframe.build_from_json(parsed, ["id", "name"])
    return dataframe.to_table(df)
}

document main {
    <- d
}

DataFrames

DataFrames provide powerful data manipulation and analysis capabilities similar to pandas or R data frames.

Building DataFrames from JSON

Create DataFrames from JSON data with specific field selection:

import "dataframe"

let d = pipeline {
    let response = http("https://jsonplaceholder.typicode.com/posts", {
        "Accept": "application/json"
    })
    let parsed = json(response["body"])
    let df = dataframe.build_from_json(parsed, ["id", "name"])
    return dataframe.to_table(df)
}

Column Operations

Rename columns and perform column-based operations:

import "dataframe"

let d = pipeline {
    let response = http("https://jsonplaceholder.typicode.com/posts", {
        "Accept": "application/json"
    })
    let parsed = json(response["body"])
    let df = dataframe.build_from_json(parsed, ["id", "name"])
    let newdf = dataframe.renamecol(df, "name", "newone")
    return dataframe.to_table(newdf)
}

Counting and Aggregation

Count specific values and create aggregations:

DataFrame Counting

Count specific values and create aggregations:

import "dataframe"

// Count specific values
let count = dataframe.count(df, "userId", "9")

// Count unique values and convert to chart data
let chartData = dataframe.countunique_tochartdata(df, "userId")

DataFrames with Charts

Use DataFrames to create dynamic charts:

DataFrames with Charts

Use DataFrames to create dynamic charts:

import "dataframe"

let d = pipeline {
    let response = http("https://jsonplaceholder.typicode.com/posts", {
        "Accept": "application/json"
    })
    let parsed = json(response["body"])
    let df = dataframe.build_from_json(parsed, ["id", "name", "userId"])
    return df
}

let p = pipeline {
    let df = <- d
    return chartdata {
        type "pie"
        x ["9", "10"]
        y [
            dataframe.count(df, "userId", "9"),
            dataframe.count(df, "userId", "10")
        ]
    }
}

let value = section {
    chart {
        type "pie"
        data <- p
    }
}

document main {
    title "Welcome to test"
    author "Sebastian Barry"
    ...value
}

Built-in Functions

Hanami provides a rich set of built-in functions for common operations.

String Functions

Functions for working with strings:

String Functions

Functions for working with strings:

len("1")     // Returns: 1
len("four")  // Returns: 4

Display Functions

Functions for formatting and displaying data:

Display Functions

Functions for formatting and displaying data:

// Pretty-print JSON or complex data
pretty(jsondata)

// Create bullet lists in sections
section {
    title "Bullet List"
    subtitle "Test Subtitle"
    body "value"
    bullet_list [
        "Item 1",
        "Item 2",
        "Item 3"
    ]
}

Image Functions

Embed images from URLs:

Image Functions

Embed images from URLs:

httpcoverimage("https://picsum.photos/id/237/200/300")

SQL Integration

Hanami can connect to databases and execute SQL queries to fetch data for your reports.

Supported Databases

  • Postgres
  • DB2 (in development)

Configuration

Database credentials can be provided through environment variables:

Bash/Shell

Environment Variables (Bash)

Set database credentials in bash/shell:

export DB_USERNAME=""
export DB_PASSWORD=""
export DB_PORT=""
export DB_TYPE=""
export DB_HOST=""
export DB_NAME=""
export DB_SCHEMA=""
export DB_SSL_MODE="require"

PowerShell

Environment Variables (PowerShell)

Set database credentials in PowerShell:

$env:DB_USERNAME=""
$env:DB_PASSWORD=""
$env:DB_PORT=""
$env:DB_TYPE=""
$env:DB_HOST=""
$env:DB_NAME=""
$env:DB_SCHEMA=""
$env:DB_SSL_MODE="require"

Using SQL in Reports

SQL queries can be executed directly within a section:

SQL in Reports

Execute SQL queries in sections:

section newSection {
    title "SQL Query Results"
    body "This SQL statement below will query the database and return a table with headers and rows of the database."
    sql("select * from ...")
}

document test {
    ...newSection
}

The sql() function executes the SQL query and renders the results as a table in your report.

Last updated: 7/26/2025