redash

package
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package redash is a minimal Redash REST API client covering query execution, ad-hoc and by saved-query ID: submit, poll, fetch, cancel, plus saved-query creation, reading and editing, reading a stored result by ID, visualization creation, editing and deletion, data-source listing and a session check for login verification.

Index

Constants

View Source
const (
	StatusPending   = 1
	StatusStarted   = 2
	StatusSuccess   = 3
	StatusFailure   = 4
	StatusCancelled = 5
)

Job statuses as defined by Redash.

Variables

View Source
var ErrQueryVersionConflict = errors.New("saved query changed on the server since it was read")

ErrQueryVersionConflict reports that a saved query changed on the server between the read that supplied QueryUpdate.Version and the update that carried it, so the update was refused rather than applied on top of an edit the caller never saw.

Functions

This section is empty.

Types

type Client

type Client struct {
	// PollInterval is the delay between job status checks.
	PollInterval time.Duration
	// contains filtered or unexported fields
}

Client talks to one Redash instance authenticated by a user API key (query API keys cannot run ad-hoc queries).

func NewClient

func NewClient(baseURL, apiKey string) *Client

NewClient returns a client for the Redash instance at baseURL. A trailing slash is trimmed so env-pair and hand-edited config URLs do not produce double-slash request paths.

func (*Client) CancelJob

func (c *Client) CancelJob(ctx context.Context, id string) error

CancelJob asks the server to stop the job.

func (*Client) CreateQuery

func (c *Client) CreateQuery(ctx context.Context, q NewQuery) (*Query, error)

CreateQuery saves a new query. Redash forces the new query to be a draft whatever the request body says, so publishing it is a second call to UpdateQuery rather than a field set here.

Redash 26.3.0 and later attach the latest result of a matching query text and data source to the new query as it is created, which is what lets a run followed by a create share results without executing them twice. Older versions link a result only when the saved query is executed, so the returned query's LatestQueryDataID is what says whether it happened — the link is committed before the response is serialized.

func (*Client) CreateVisualization

func (c *Client) CreateVisualization(ctx context.Context, v NewVisualization) (*Visualization, error)

CreateVisualization attaches a new visualization to a query and returns it as the server now holds it.

func (*Client) DeleteVisualization

func (c *Client) DeleteVisualization(ctx context.Context, id int) error

DeleteVisualization removes the visualization from its query.

func (*Client) GetQuery

func (c *Client) GetQuery(ctx context.Context, id int) (*Query, error)

GetQuery reads one saved query, including the Version an update needs.

func (*Client) GetQueryResult

func (c *Client) GetQueryResult(ctx context.Context, resultID int) (*QueryResult, error)

GetQueryResult reads one stored result by ID. Paired with a query's LatestQueryDataID it is how the result the query page shows is read without executing anything, which is what lets a chart's column names be checked against it.

func (*Client) GetSession

func (c *Client) GetSession(ctx context.Context) error

GetSession verifies the base URL and API key with an authenticated request; auth login calls this before saving anything.

func (*Client) ListDataSources

func (c *Client) ListDataSources(ctx context.Context) ([]DataSource, error)

ListDataSources returns the data sources visible to the API key.

func (*Client) ListQueries

func (c *Client) ListQueries(ctx context.Context, opts QueryListOptions) ([]Query, int, error)

ListQueries returns up to opts.Limit saved queries and the total number the server holds, which is what lets a caller tell that the limit truncated the listing rather than that it saw everything.

Without a search term the server orders them newest first; with one the order is its own search ranking, so no order is promised here.

The API paginates, so this walks the pages itself. It stops from the count the server reports rather than by probing for an empty page: Redash refuses a page past the end with 400 "Page is out of range".

func (*Client) QueryURL

func (c *Client) QueryURL(id int) string

QueryURL is where a saved query is read in a browser. The API returns no URL of its own, so it is built from the base URL NewClient normalised.

func (*Client) QueryURLPrefix

func (c *Client) QueryURLPrefix() string

QueryURLPrefix is what every query URL on this instance begins with. A caller reading a query URL matches against this rather than rebuilding it from the base URL, so the two directions cannot drift apart.

func (*Client) RefreshQuery

func (c *Client) RefreshQuery(ctx context.Context, id int, parameters map[string]any) (*QueryResult, error)

RefreshQuery executes the saved query on the server and returns the fetched result. Unlike RunQuery, which runs SQL the server has never seen, this is the execution the query page itself makes: Redash records it against the saved query, so the cached result everyone sees advances — as long as parameters render the query to the text its stored hash was taken over.

parameters supplies a value for every placeholder the query has; one left uncovered fails the execution on the server rather than here.

func (*Client) RunQuery

func (c *Client) RunQuery(ctx context.Context, query string, dataSourceID int) (*QueryResult, error)

RunQuery submits an ad-hoc query (cache always bypassed via max_age=0) and polls until it finishes, returning the fetched result.

func (*Client) UpdateQuery

func (c *Client) UpdateQuery(ctx context.Context, id int, u QueryUpdate) (*Query, error)

UpdateQuery changes the fields u sets on the saved query and returns it as the server now holds it. When u carries a Version, the 409 a stale one earns is wrapped in ErrQueryVersionConflict; without one the server applies the update unconditionally, so a 409 means something else and is returned as it came.

func (*Client) UpdateVisualization

func (c *Client) UpdateVisualization(ctx context.Context, id int, u VisualizationUpdate) (*Visualization, error)

UpdateVisualization changes the fields u sets and returns the visualization as the server now holds it. Redash ignores a query_id in the body, so a visualization cannot be moved between queries this way.

type Column

type Column struct {
	Name         string `json:"name"`
	FriendlyName string `json:"friendly_name"`
	Type         string `json:"type"`
}

Column describes one result column. FriendlyName and Type can be null in real Redash responses.

type DataSource

type DataSource struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

DataSource is one Redash data source.

type Job

type Job struct {
	ID            string `json:"id"`
	Status        int    `json:"status"`
	Error         string `json:"error"`
	QueryResultID int    `json:"query_result_id"`
}

Job is the server-side execution of one submitted query.

type NewQuery

type NewQuery struct {
	Name         string `json:"name"`
	Query        string `json:"query"`
	DataSourceID int    `json:"data_source_id"`
	Description  string `json:"description,omitempty"`
	// Options carries the parameter definitions the new query is saved
	// with. Redash recomputes the query hash as it saves, so defaults set
	// here link an existing result to the query at creation time; nil
	// leaves the options key out.
	Options *QueryOptions `json:"options,omitempty"`
}

NewQuery holds the fields the API accepts when a saved query is created.

type NewVisualization

type NewVisualization struct {
	QueryID int                        `json:"query_id"`
	Type    string                     `json:"type"`
	Name    string                     `json:"name"`
	Options map[string]json.RawMessage `json:"options"`
}

NewVisualization holds the fields the API accepts when a visualization is created. Redash does not validate Options at all, so a malformed one is stored without complaint and shows up only as a blank chart in the UI.

type Query

type Query struct {
	ID           int    `json:"id"`
	Name         string `json:"name"`
	Description  string `json:"description"`
	Query        string `json:"query"`
	DataSourceID int    `json:"data_source_id"`
	IsDraft      bool   `json:"is_draft"`
	// Version is what an update sends back to prove it was composed
	// against the query as it stands; Redash refuses one carrying a stale
	// value.
	Version int `json:"version"`
	// LatestQueryDataID is the result Redash shows on the query page, and
	// draws every chart on it from. Zero means the query has none, which is
	// what a query nobody has executed reads back as.
	LatestQueryDataID int `json:"latest_query_data_id"`
	// Options carries the settings the query holds beside its SQL. An
	// update replaces the whole object, so it is decoded in a form that
	// survives being written back: see QueryOptions.
	Options QueryOptions `json:"options"`
	// Visualizations is the charts attached to the query. Only reading one
	// query carries them — the listing endpoints leave the key out — and
	// they are the only way to reach a visualization at all, since Redash
	// has no endpoint that reads one by its ID.
	Visualizations []Visualization `json:"visualizations"`
}

Query is a saved Redash query.

type QueryListOptions

type QueryListOptions struct {
	// Search is the API's q full-text search. Empty means no filtering.
	Search string
	// Mine lists only the caller's own queries.
	Mine bool
	// Limit caps how many queries are returned. It must be at least 1;
	// the server refuses the page size a smaller one would ask for.
	Limit int
}

QueryListOptions narrows what ListQueries returns.

type QueryOptions

type QueryOptions struct {
	// Parameters is the parameter definitions, in the order they are
	// stored. Nil means the object had no parameters key, which is left
	// out again on the way back rather than written as an empty list.
	Parameters []QueryParameter
	// Extra is every other key of the object, kept as it arrived.
	Extra map[string]json.RawMessage
}

QueryOptions is a saved query's options object. Redash's update replaces it wholesale, so a caller editing one key has to send back everything else as it was; Extra is what makes that possible for the keys rdsh has no field for. A query saved through the API carries no options at all, which reads back as the zero value rather than as a failure.

func (QueryOptions) MarshalJSON

func (o QueryOptions) MarshalJSON() ([]byte, error)

MarshalJSON writes Extra back with the parameter definitions in place of the key they were read from.

func (*QueryOptions) UnmarshalJSON

func (o *QueryOptions) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the object into the parameter definitions and Extra.

The decoder is built here rather than taken from the caller because encoding/json does not carry UseNumber into a custom UnmarshalJSON: a plain json.Unmarshal would turn a numeric default into a float64 and lose the text QueryParameter.Value promises to reproduce.

type QueryParameter

type QueryParameter struct {
	Name  string
	Title string
	Type  string
	// Value is the stored default, decoded as it came: numbers stay
	// json.Number, so sending one back reproduces the text Redash hashed
	// the query with. A parameter defined without a default is nil.
	Value any
	// Regex is the pattern a text-pattern parameter's value must match in
	// full. Empty on every other type.
	Regex string
	Extra map[string]json.RawMessage
}

QueryParameter is one parameter defined on a saved query. The fields are the scalar parameter kinds rdsh can express; Extra carries everything else — the fields a range, enum or dropdown-query parameter needs — so a definition rdsh does not understand still survives an update.

func (QueryParameter) MarshalJSON

func (p QueryParameter) MarshalJSON() ([]byte, error)

MarshalJSON writes the definition back, leaving out the fields that were never set. A null value reads as "no default" exactly as an absent one does, so it is left out too — but an empty one is not: see below.

func (*QueryParameter) UnmarshalJSON

func (p *QueryParameter) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes one definition, keeping the keys rdsh has no field for. It builds its own decoder for the same reason QueryOptions does.

type QueryResult

type QueryResult struct {
	Columns []Column
	Rows    []map[string]any
}

QueryResult holds the fetched result data. Rows are maps keyed by column name; output ordering must come from Columns.

type QueryUpdate

type QueryUpdate struct {
	Name        *string `json:"name,omitempty"`
	Description *string `json:"description,omitempty"`
	Query       *string `json:"query,omitempty"`
	IsDraft     *bool   `json:"is_draft,omitempty"`
	// Options replaces the query's whole options object, so it has to be
	// composed from one that was just read rather than from nothing. Nil
	// leaves the key out, which is what keeps an update of the query's
	// metadata alone from clearing its parameter definitions.
	Options *QueryOptions `json:"options,omitempty"`
	// Version opts into the server's conflict check: set it to the version
	// of the query this update was composed from and a competing edit fails
	// the update instead of being silently overwritten. Left nil, the
	// server applies the update as a last write.
	Version *int `json:"version,omitempty"`
}

QueryUpdate holds the fields to change on a saved query; a nil field is left as it is. Pointers rather than plain fields so clearing a value (an empty description) stays distinguishable from not touching it.

type Visualization

type Visualization struct {
	ID   int    `json:"id"`
	Type string `json:"type"`
	Name string `json:"name"`
	// Options is the settings blob the front end renders from, kept key by
	// key as it arrived rather than decoded into fields. Redash stores it
	// without validating it and an update replaces every key the request
	// carries, so an edit has to be able to send back what it never meant
	// to touch — the same problem QueryOptions.Extra solves, over a schema
	// with far more keys and no field here worth naming.
	Options map[string]json.RawMessage `json:"options"`
}

Visualization is one chart or table shown on a saved query's page.

type VisualizationUpdate

type VisualizationUpdate struct {
	Type *string `json:"type,omitempty"`
	Name *string `json:"name,omitempty"`
	// Options is a pointer for the same reason Type and Name are: an empty
	// object is a value — it resets the visualization to the front end's own
	// defaults — and a plain map with omitempty could not tell that apart
	// from an edit that leaves the options alone.
	Options *map[string]json.RawMessage `json:"options,omitempty"`
}

VisualizationUpdate holds the fields to change on a visualization; a nil field is left as it is. Options replaces the whole blob, so it has to be composed from one that was just read rather than from nothing — which is what keeps a rename from clearing the chart's settings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL