JSON extension for Dashfy - Display data from any JSON/REST API with flexible rendering options.
This extension provides widgets to fetch, transform, and visualize JSON data from REST APIs with support for custom templates, status monitoring, and key-value displays.
- 🌐 Universal API support: Connect to any REST API that returns JSON
- 🎨 Flexible rendering: Templates, React components, or raw JSON display
- 🔑 Key-value display: Extract and show specific fields from JSON responses
- 📊 Status monitoring: Evaluate assertions and display status indicators
- 🔄 Data transformation: Transform API responses before rendering
- 🛣️ JSONPath support: Extract nested data using simplified JSONPath expressions
- 🔐 Authentication: Support for custom headers (Bearer tokens, API keys, etc.)
- ⚡ Real-time updates: Automatic data refresh via WebSocket subscriptions
- 🎨 Theme support: Works with all Dashfy themes (light/dark mode)
Install with your favorite package manager:
npm install @getdashfy/ext-jsonpnpm add @getdashfy/ext-jsonyarn add @getdashfy/ext-jsonbun add @getdashfy/ext-jsonRegister the JSON API client in your Dashfy server (dashfy.server.ts):
import { Dashfy } from '@getdashfy/server'
import { createJsonClient } from '@getdashfy/ext-json/client'
// Create a new Dashfy server instance
const dashfy = new Dashfy()
// Load dashboard configuration
await dashfy.configureFromFile('./dashfy.config.yml')
// Register JSON API (all options are optional)
dashfy.registerApi(
'json',
createJsonClient({
baseUrl: 'https://api.example.com',
headers: { Authorization: `Bearer ${process.env.API_TOKEN}` },
timeout: 5_000,
}),
)
// Start server
await dashfy.start()Register JSON widgets in your React application (App.tsx):
import { WidgetRegistry } from '@getdashfy/ui'
import { CustomJson, JsonKeys, JsonStatus } from '@getdashfy/ext-json'
// Register JSON extension
WidgetRegistry.addExtension('json', {
CustomJson,
JsonKeys,
JsonStatus,
})Add JSON widgets to your dashboard configuration (dashfy.config.yml):
dashboards:
- title: API Dashboard
columns: 3
rows: 2
widgets:
- extension: json
widget: JsonKeys
title: User Profile
url: https://api.example.com/user
keys:
- name
- email
- location
x: 0
y: 0
columns: 1
rows: 1
- extension: json
widget: JsonStatus
title: API Health
url: https://api.example.com/health
statuses:
- assert: equals(status, ok)
status: success
label: API Online
- assert: equals(status, degraded)
status: warning
label: API Degraded
x: 1
y: 0
columns: 1
rows: 1createJsonClient({
// Base URL prepended to all requests (optional)
baseUrl: 'https://api.example.com',
// Default headers included in all requests (optional)
headers: {
Authorization: 'Bearer your-token',
'Content-Type': 'application/json',
},
// Request timeout in milliseconds (default: 10_000)
timeout: 5_000,
})Use environment variables for sensitive configuration:
API_BASE_URL=https://api.example.com
API_TOKEN=your-secret-tokencreateJsonClient({
baseUrl: process.env.API_BASE_URL,
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
},
})createJsonClient registers a single endpoint. Widgets subscribe to it through the endpoint parameter (default get), and you can call it from your own custom widgets.
| Endpoint | Parameters | Returns |
|---|---|---|
get |
url, headers, method, body, path |
{ data, url, timestamp } |
The method and body parameters are accepted by the client but not surfaced by any built-in widget, so they are available for custom widgets (e.g. POST requests). When path is provided, the response is narrowed with a simplified JSONPath expression (see JSONPath support).
Display specific key-value pairs extracted from a JSON response. Supports nested property access using dot notation.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string | yes | - | URL to fetch the JSON data |
keys |
string[] | yes | - | Array of keys to extract (supports dot notation) |
title |
string | no | "JSON Keys" | Custom widget title |
subject |
string | no | - | Custom widget subject |
headers |
Record<string,string> | no | - | HTTP headers to send with the request |
path |
string | no | - | JSONPath expression to extract specific data |
api |
string | no | "json" | API subscription ID |
endpoint |
string | no | "get" | API endpoint to call |
Example:
- extension: json
widget: JsonKeys
title: User Profile
url: https://api.example.com/user/123
headers:
Authorization: Bearer token
keys:
- name
- email
- profile.age
- stats.posts
columns: 1
rows: 1Use dot notation to access nested properties: user.name reads data.user.name, stats.followers reads data.stats.followers.
Display JSON data with flexible rendering options: Eta templates, React components, or raw JSON.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string | yes | - | URL to fetch the JSON data |
title |
string | no | "JSON Data" | Custom widget title |
subject |
string | no | - | Custom widget subject |
headers |
Record<string,string> | no | - | HTTP headers to send with the request |
path |
string | no | - | JSONPath expression to extract specific data |
template |
string | no | - | Eta template string for HTML rendering |
render |
function | string | no | - | Custom React render function |
transform |
function | string | no | - | Transform function to process data |
showRaw |
boolean | no | true | Show raw JSON if no render/template provided |
api |
string | no | "json" | API subscription ID |
endpoint |
string | no | "get" | API endpoint to call |
Example (template):
- extension: json
widget: CustomJson
title: Weather
url: https://api.example.com/weather
template: |
<div>
<h2><%= data.city %></h2>
<p>Temperature: <%= data.temp %>°C</p>
<p>Condition: <%= data.condition %></p>
</div>
columns: 2
rows: 1Example (React render function):
<CustomJson
title="Repository Stats"
url="https://api.github.com/repos/facebook/react"
transform={(data) => ({
name: data.name,
stars: data.stargazers_count,
forks: data.forks_count,
})}
render={(data) => (
<div>
<h2>{data.name}</h2>
<p>⭐ {data.stars} stars</p>
<p>🍴 {data.forks} forks</p>
</div>
)}
/>Example (raw JSON):
- extension: json
widget: CustomJson
title: API Response
url: https://api.example.com/data
showRaw: true
columns: 2
rows: 1Note: string-based
renderfunctions (from YAML/JSON config) do not support JSX. Usetemplatefor HTML rendering, or pass an actual function in code for JSX.
Templates use the Eta template engine:
<!-- Output value -->
<%= data.field %>
<!-- Conditional -->
<% if (data.count > 5) { %> Many items <% } else { %> Few items <% } %>
<!-- Loop -->
<ul>
<% data.items.forEach(item => { %>
<li><%= item.name %></li>
<% }) %>
</ul>
<!-- Expressions -->
<p>Total: <%= data.price * data.quantity %></p>Display status indicators based on assertions evaluated against JSON data.
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url |
string | yes | - | URL to fetch the JSON data |
statuses |
StatusAssertion[] | yes | - | Array of status assertions to evaluate |
title |
string | no | "JSON Status" | Custom widget title |
subject |
string | no | - | Custom widget subject |
headers |
Record<string,string> | no | - | HTTP headers to send with the request |
path |
string | no | - | JSONPath expression to extract specific data |
api |
string | no | "json" | API subscription ID |
endpoint |
string | no | "get" | API endpoint to call |
StatusAssertion:
| Field | Type | Required | Description |
|---|---|---|---|
assert |
string | yes | Assertion expression (see formats below) |
status |
"success" | "warning" | "error" | "unknown" | yes | Status to display if assertion passes |
label |
string | no | Optional label to display with status |
Example:
- extension: json
widget: JsonStatus
title: API Health
url: https://api.example.com/health
statuses:
- assert: equals(status, ok)
status: success
label: API Online
- assert: equals(status, degraded)
status: warning
label: API Degraded
- assert: equals(status, down)
status: error
label: API Down
columns: 1
rows: 1| Format | Description |
|---|---|
equals(key, value) |
The value strictly equals the expectation |
contains(key, substring) |
The value contains the substring |
matches(key, pattern) |
The value matches a regular expression |
truthy(key) |
The value is truthy |
falsy(key) |
The value is falsy |
Assertions are evaluated in order, and the last matching assertion wins. Put a broad default first and more specific conditions after it:
statuses:
# Default status
- assert: truthy(status)
status: unknown
label: Unknown Status
# Specific conditions (evaluated last, take precedence)
- assert: equals(status, operational)
status: success
label: All Systems Operational
- assert: equals(status, outage)
status: error
label: Service Outagedashboards:
- title: API Monitoring
columns: 3
rows: 1
widgets:
# API status
- extension: json
widget: JsonStatus
title: API Health
url: https://api.example.com/health
statuses:
- assert: equals(status, ok)
status: success
label: Operational
- assert: equals(status, degraded)
status: warning
label: Degraded
x: 0
y: 0
columns: 1
rows: 1
# Key metrics
- extension: json
widget: JsonKeys
title: Metrics
url: https://api.example.com/metrics
keys:
- requests.total
- requests.success
- latency.avg
- uptime
x: 1
y: 0
columns: 1
rows: 1
# Custom display
- extension: json
widget: CustomJson
title: System Info
url: https://api.example.com/system
template: |
<div>
<h3><%= data.name %></h3>
<p>Version: <%= data.version %></p>
<p>Uptime: <%= data.uptime %> days</p>
</div>
x: 2
y: 0
columns: 1
rows: 1The path parameter narrows the response before it reaches a widget. This extension implements a simplified subset of JSONPath, not the full specification:
| Syntax | Description |
|---|---|
$ |
The entire response (root) |
$.user.name |
Dot notation for nested properties |
user.name |
Leading $. is optional |
$.items[0] |
A specific array element by index |
$.items[*] |
The entire array |
- extension: json
widget: JsonKeys
url: https://api.example.com/data
path: $.users[0] # Extract the first user, then read its keys
keys:
- name
- emailPass credentials through request headers, either per widget or as client defaults:
# Bearer token
headers:
Authorization: Bearer your-token
# API key
headers:
X-API-Key: your-api-key
# Basic auth (base64 encoded)
headers:
Authorization: Basic dXNlcjpwYXNzIf you encounter CORS errors, ensure the API server includes appropriate CORS headers, or configure a proxy in your Dashfy server:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Solution: Verify that your API token/key is valid and has the necessary permissions.
Solution: Confirm your expression uses the supported simplified syntax above. Full JSONPath features (filters, recursive descent, unions) are not implemented.
Solution: Check your Eta template syntax and ensure all referenced variables exist on the data object.
Contributions are welcome. For issues and pull requests related to the extension, use the dashfy/dashfy-ext-json repository. Framework contributions belong in dashfy/dashfy.
Join the community on Dashfy's Discord server to discuss the project, ask questions, or get help.
Join the conversation on X (Twitter) and follow @dashfydev for updates and announcements.
This project is licensed under the AGPL-3.0 License - see the LICENSE file for details.