We're building a golang SDK for Redash and we're planning to open source it 💙

Hi Redash Community!

We (RecoLabs, a stealth startup) are building a golang SDK for Redash, and we’re planning to open-source it. We’d love to coordinate with the community before just publishing it, so here goes :rocket:

What is it?

From the documentation of the go package:

// redashclient is a go wrapper to Redash's REST API.
// redashclient provides a go API to set up and manage a remote redash client programmatically.

And from the README:

This is a simple SDK for the programmatic management of Redash. We created this client based on the python code of version 10.1.0 of Redash.

What’s included?

  1. Easy to use Go client that covers some parts of the API.
  2. Swagger definition of the Redash API - we would love to coordinate with the community here and contribute this to the main project in the future.
  3. Documentation and examples.
  4. Earthly-based build pipeline (lint and test).
  5. Many linters with golangci-lint and good test coverage.

Which parts of the API are covered?

  • Data Sources
  • Queries
  • Visualizations
  • Users

Some of these resources might only be partially covered.

Why do this?

We needed a way to programmatically control our self-hosted Redash instance from our backend services - we developed a custom dashboard screen in our product and Redash solved many issues for us, so we decided to use it as both the backend and the visualization engine (with embedded visualizations).

Examples

Subsection of the Swagger file

Client usage

List all queries

import (
    redashclient "github.com/[REDACTED]/redashClient"
    "github.com/[REDACTED]/gen/client"
)

redashClient := redashclient.NewClient(
	 "{API_KEY}",
	 &client.TransportConfig{
		 Host: "{HOST_ADDRESS}",
	 })

// Calls in the client are of the form:
//  client.<Queries/Visualizations/Users/DataSources>.<Method>(...)
// For example:
// List the current queries in Redash
allQueries, err := redashClient.Queries.List()

Get a visualization’s embed URL

queryID := 1
visualizationID := 1
queryAPIKey := "{API_KEY}"
visualizationUrl, err := redashClient.Visualizations.GetURL(visualizationID, queryID, queryAPIKey)
`

What’s next?

Once we collect a bit more feedback about the package internally and from y’all here in the community, we plan to release it under BSD 2-Clause “Simplified” License. Hopefully, we’ll be able to make this happen very soon.

3 Likes

That’ll be pretty welcome. I started down this track a while back, but ran out of time.

One of the weird things I found with the Redash API, was that sometimes the JSON that’s returned changes field types depending on part of the returned data.

That made my initial Go efforts (with Go being a strongly typed language) more of a hassle that it needed to be. Wasn’t impossible to work around, just an unfortunate inconvenience.

Hopefully that strangeness doesn’t get exposed through your Go SDK. :smile:

1 Like

On that note this is the initial Redash end points list I threw together when looking over the API code.

May or may not be useful, depending on how far you’ve progressed already. :smile:

(tried attaching this as a file, but Discourse only seems to allow for pictures. :man_facepalming:

const (
	EndpointAdminQueriesOutdated = "/api/admin/queries/outdated"
	EndpointAdminQueriesRqStatus = "/api/admin/queries/rq_status"
	EndpointAlerts               = "/api/alerts"
	EndpointConfig               = "/api/config"
	EndpointDashboards           = "/api/dashboards"
	EndpointDashboardsFavorites  = "/api/dashboards/favorites"
	EndpointDashboardsTags       = "/api/dashboards/tags"
	EndpointDashboardsMy         = "/api/dashboards/my"
	EndpointDataSources          = "/api/data_sources"
	EndpointDataSourcesTypes     = "/api/data_sources/types"
	EndpointDestinations         = "/api/destinations"
	EndpointDestinationsTypes    = "/api/destinations/types"
	EndpointEvents               = "/api/events"
	EndpointForgot               = "/api/forgot"
	EndpointGroups               = "/api/groups"
	EndpointOrgStatus            = "/api/organization/status"
	EndpointPing                 = "/api/ping"
	EndpointQueryResults         = "/api/query_results"
	EndpointQueries              = "/api/queries"
	EndpointQueriesArchive       = "/api/queries/archive"
	EndpointQueriesFavorites     = "/api/queries/favorites"
	EndpointQueriesFormat        = "/api/queries/format"
	EndpointQueriesMy            = "/api/queries/my"
	EndpointQueriesRecent        = "/api/queries/recent"
	EndpointQueriesSearch        = "/api/queries/search"
	EndpointQueriesTags          = "/api/queries/tags"
	EndpointQuerySnippets        = "/api/query_snippets"
	EndpointSession              = "/api/session"
	EndpointSettingsOrg          = "/api/settings/organization"
	EndpointUsers                = "/api/users"
	EndpointVisualizations       = "/api/visualizations"
	EndpointWidgets              = "/api/widgets"
)

// Not sure how to represent these in Go.  Probably need special handling for each one
const (
	// Alert
	EndpointAlertId      = "/api/alerts/<alert_id>"
	EndpointAlertIdMute  = "/api/alerts/<alert_id>/mute"
	EndpointAlertIdSubs  = "/api/alerts/<alert_id>/subscriptions"
	EndpointAlertIdSubId = "/api/alerts/<alert_id>/subscriptions/<subscriber_id>"

	// Dashboard
	EndpointDashboardId       = "/api/dashboards/<dashboard_id>"
	EndpointDashboardFavorite = "/api/dashboards/<object_id>/favorite"
	EndpointDashboardIdShare  = "/api/dashboards/<dashboard_id>/share"
	EndpointDashboardPubToken = "/api/dashboards/public/<token>"

	// Databricks
	EndpointDatabricksDbId        = "/api/databricks/databases/<data_source_id>"
	EndpointDatabricksDbTables    = "/api/databricks/databases/<data_source_id>/<database_name>/tables"
	EndpointDatabricksDbTableCols = "/api/databricks/databases/<data_source_id>/<database_name>/columns/<table_name>"

	// Data source
	EndpointDataSourceId       = "/api/data_sources/<data_source_id>"
	EndpointDataSourceIdSchema = "/api/data_sources/<data_source_id>/schema"
	EndpointDataSourceIdPause  = "/api/data_sources/<data_source_id>/pause"
	EndpointDataSourceIdTest   = "/api/data_sources/<data_source_id>/test"

	// Destination
	EndpointDestinationId = "/api/destinations/<destination_id>"

	// Group
	EndpointGroupId             = "/api/groups/<group_id>"
	EndpointGroupIdMembers      = "/api/groups/<group_id>/members"
	EndpointGroupIdMemberId     = "/api/groups/<group_id>/members/<user_id>"
	EndpointGroupIdDataSources  = "/api/groups/<group_id>/data_sources"
	EndpointGroupIdDataSourceId = "/api/groups/<group_id>/data_sources/<data_source_id>"

	// Job
	EndpointJobId = "/api/jobs/<job_id>"

	// Query
	EndpointQueryId                       = "/api/queries/<query_id>"
	EndpointQueryIdAcl                    = "/api/<object_type>/<object_id>/acl"
	EndpointQueryIdAclAccessType          = "/api/<object_type>/<object_id>/acl/<access_type>"
	EndpointQueryIdDropdown               = "/api/queries/<query_id>/dropdown"
	EndpointQueryIdDropdownId             = "/api/queries/<query_id>/dropdowns/<dropdown_query_id>"
	EndpointQueryIdFavorite               = "/api/queries/<query_id>/favorite"
	EndpointQueryIdFork                   = "/api/queries/<query_id>/fork"
	EndpointQueryIdJobId                  = "/api/queries/<query_id>/jobs/<job_id>"
	EndpointQueryIdRefresh                = "/api/queries/<query_id>/refresh"
	EndpointQueryIdRegenApiKey            = "/api/queries/<query_id>/regenerate_api_key"
	EndpointQueryIdResults                = "/api/queries/<query_id>/results"
	EndpointQueryIdResultsFileType        = "/api/queries/<query_id>/results.<filetype>"
	EndpointQueryIdResultsQueryIdFileType = "/api/queries/<query_id>/results/<query_result_id>.<filetype>"

	// Query Result
	EndpointQueryResultQueryId         = "/api/query_results/<query_result_id>"
	EndpointQueryResultQueryIdFileType = "/api/query_results/<query_result_id>.<filetype>"

	// Query Snippet
	EndpointQuerySnippetId = "/api/query_snippets/<snippet_id>"

	// User
	EndpointUserId            = "/api/users/<user_id>"
	EndpointUserIdDisable     = "/api/users/<user_id>/disable"
	EndpointUserIdInvite      = "/api/users/<user_id>/invite"
	EndpointUserIdResetPw     = "/api/users/<user_id>/reset_password"
	EndpointUserIdRegenApiKey = "/api/users/<user_id>/regenerate_api_key"

	// Widget
	EndpointWidgetId = "/api/widgets/<int:widget_id>"
)
1 Like

@ShayNehmad-RecoLabs Anything publicly available to try yet? :smile:

Asking because I’m writing some internal-use Redash utilities now (in Go), so figured that if your library has something able to be tried out then I might as well give it a go.

If not, I’ll just use the initial bits I was working on a while ago as the foundation piece. That’ll work too. :slight_smile:

1 Like

We’re actually aiming to publicly release today! So stay tuned :rocket:

:rocket: :rocket: :rocket:

1 Like

Excellent. I’ll have a go with that over the next few days. :smile:

@ShayNehmad-RecoLabs is there any functionality in your sdk to extract the list of dashboards , similar to redash api /api/dashboards ?