http

package module
v0.0.0-...-20c0713 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2025 License: MIT Imports: 18 Imported by: 2

README

rqlite-go-http

Circle CI Go Report Card Go Reference

rqlite-go-http is a Go client for rqlite that interacts directly with the rqlite HTTP API, providing little abstraction. It can be used on its own or as a foundation for higher-level libraries.

This library offers support for:

  • Executing SQL statements (INSERT, UPDATE, DELETE)
  • Running queries (SELECT)
  • Handling both read and write statements in a single request via the Unified Endpoint.
  • Backing up and restoring data to your rqlite system
  • Booting a rqlite node from a SQLite database file
  • Checking node status, diagnostic info, cluster membership, and readiness
  • Ability to customize HTTP communications for control over TLS, mutual TLS, timeouts, etc.

Check out the documentation for more details.

Installation

go get github.com/rqlite/rqlite-go-http

Example use

package main

import (
	"context"
	"fmt"

	rqlitehttp "github.com/rqlite/rqlite-go-http"
)

func main() {
	// Create a client pointing to a rqlite node
	client, err := rqlitehttp.NewClient("http://localhost:4001", nil)
	if err != nil {
		panic(err)
	}

	// Optionally set Basic Auth
	client.SetBasicAuth("user", "password")

	// Create a table.
	resp, err := client.ExecuteSingle(context.Background(), "CREATE TABLE foo (id INTEGER PRIMARY KEY, name TEXT)")
	if err != nil {
		panic(err)
	}

	// Insert a record.
	resp, err = client.Execute(
		context.Background(),
		rqlitehttp.SQLStatements{
			{
				SQL:              "INSERT INTO foo(name) VALUES(?)",
				PositionalParams: []any{"fiona"},
			},
		},
	)
	if err != nil {
		panic(err)
	}
	fmt.Printf("ExecuteResponse: %+v\n", resp)

	// Query the newly created table
	qResp, err := client.QuerySingle(context.Background(), "SELECT * FROM foo")
	if err != nil {
		panic(err)
	}
	fmt.Printf("QueryResponse: %+v\n", qResp)
}

Documentation

Index

Constants

View Source
const (
	ReadConsistencyLevelUnknown = iota
	ReadConsistencyLevelNone
	ReadConsistencyLevelWeak
	ReadConsistencyLevelStrong
	ReadConsistencyLevelLinearizable
	ReadConsistencyLevelAuto
)

Variables

View Source
var (
	// ErrNoHostsAvailable is returned when no hosts are available.
	ErrNoHostsAvailable = errors.New("no hosts available")

	// ErrDuplicateAddresses is returned when duplicate addresses are provided
	// to a balancer.
	ErrDuplicateAddresses = errors.New("duplicate addresses provided")
)

Functions

func DefaultHTTPClient

func DefaultHTTPClient() *http.Client

DefaultHTTPClient returns an HTTP client with a 5-second timeout.

func NewHTTPMutualTLSClient

func NewHTTPMutualTLSClient(clientCertPath, clientKeyPath, caCertPath string) (*http.Client, error)

NewHTTPMutualTLSClient returns an HTTP client configured for mutual TLS. It accepts paths for the client cert, client key, and trusted CA.

func NewHTTPTLSClient

func NewHTTPTLSClient(caCertPath string) (*http.Client, error)

NewHTTPTLSClient returns an HTTP client configured for simple TLS, using the provided CA certificate.

func NewHTTPTLSClientInsecure

func NewHTTPTLSClientInsecure() (*http.Client, error)

NewHTTPTLSClientInsecure returns an HTTP client configured for simple TLS, but skipping server certificate verification. The client's timeout is set as 5 seconds.

Types

type BackupOptions

type BackupOptions struct {
	// Format can be "sql" if a SQL text dump is desired, otherwise an empty string
	// (or anything else) means a binary SQLite file is returned.
	Format string `uvalue:"fmt,omitempty"`

	// If set, request that the backup be vacuumed before returning it.
	Vacuum bool `uvalue:"vacuum,omitempty"`

	// If set, request that the backup be GZIP-compressed.
	Compress bool `uvalue:"compress,omitempty"`

	// If set, ask a Follower not to forward the request to the Leader and instead
	// read its local database and return that as the backup data.
	NoLeader bool `uvalue:"noleader,omitempty"`

	// If set, instruct a Follower to return a redirect to the Leader instead of forwarding.
	Redirect bool `uvalue:"redirect,omitempty"`
}

BackupOptions holds optional parameters for a backup operation.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is the main type through which rqlite is accessed.

func NewClient

func NewClient(baseURL string, httpClient *http.Client) (*Client, error)

NewClient creates a new Client with default settings. If httpClient is nil, the the default client is used.

func (*Client) Backup

func (c *Client) Backup(ctx context.Context, opts BackupOptions) (io.ReadCloser, error)

Backup requests a copy of the SQLite database from the node. The caller must close the returned ReadCloser when done, regardless of any error.

func (*Client) Boot

func (c *Client) Boot(ctx context.Context, r io.Reader) error

Boot streams a raw SQLite file into a single-node system, effectively initializing the underlying SQLite database from scratch. This is done via a POST to /boot.

func (*Client) Close

func (c *Client) Close() error

Close closes the client and should be called when the client is no longer needed.

func (*Client) Execute

func (c *Client) Execute(ctx context.Context, statements SQLStatements, opts *ExecuteOptions) (retEr *ExecuteResponse, retErr error)

Execute executes one or more SQL statements (INSERT, UPDATE, DELETE) using /db/execute.

func (*Client) ExecuteSingle

func (c *Client) ExecuteSingle(ctx context.Context, statement string, args ...any) (*ExecuteResponse, error)

ExecuteSingle performs a single write operation (INSERT, UPDATE, DELETE) using /db/execute. args should be a single map of named parameters, or a slice of positional parameters. It is the caller's responsibility to ensure the correct number and type of parameters.

func (*Client) Expvar

func (c *Client) Expvar(ctx context.Context) (json.RawMessage, error)

Expvar returns the expvar data from the node.

func (*Client) Load

func (c *Client) Load(ctx context.Context, r io.Reader, opts LoadOptions) error

Load streams data from r into the node, to load or restore data. Load automatically detects the format of the data, and can handle both plain text and SQLite binary data.

func (*Client) Nodes

func (c *Client) Nodes(ctx context.Context) (json.RawMessage, error)

Nodes returns the list of known nodes in the cluster.

func (*Client) PromoteErrors

func (c *Client) PromoteErrors(b bool)

PromoteErrors enables or disables the promotion of statement-level errors to Go errors.

By default an operation on the client only returns an error if there is a failure at the HTTP level. If this method is called with true, then the client will also return an error if there is any failure at the statement level, setting the returned error to the first statement-level error encountered.

func (*Client) Query

func (c *Client) Query(ctx context.Context, statements SQLStatements, opts *QueryOptions) (retQr *QueryResponse, retErr error)

Query performs a read operation (SELECT) using /db/query.

func (*Client) QuerySingle

func (c *Client) QuerySingle(ctx context.Context, statement string, args ...any) (*QueryResponse, error)

QuerySingle performs a single read operation (SELECT) using /db/query. args should be a single map of named parameters, or a slice of positional parameters. It is the caller's responsibility to ensure the correct number and type of parameters.

func (*Client) Ready

func (c *Client) Ready(ctx context.Context) ([]byte, error)

Ready returns the readiness of the node.

func (*Client) RemoveNode

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

RemoveNode removes a node from the cluster. The node is identified by its ID.

func (*Client) Request

func (c *Client) Request(ctx context.Context, statements SQLStatements, opts *RequestOptions) (rr *RequestResponse, retErr error)

Request sends both read and write statements in a single request using /db/request.

func (*Client) RequestSingle

func (c *Client) RequestSingle(ctx context.Context, statement string, args ...any) (*RequestResponse, error)

RequestSingle sends a single statement, which can be either a read or write. args should be a single map of named parameters, or a slice of positional parameters. It is the caller's responsibility to ensure the correct number and type of parameters.

func (*Client) SetBasicAuth

func (c *Client) SetBasicAuth(username, password string)

SetBasicAuth configures the client to use Basic Auth for all subsequent requests. Pass empty strings to disable Basic Auth.

func (*Client) Status

func (c *Client) Status(ctx context.Context) (json.RawMessage, error)

Status returns the status of the node.

func (*Client) Version

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

Version returns the version of software running on the node.

type ExecuteOptions

type ExecuteOptions struct {
	// Transaction indicates whether the statements should be enclosed in a transaction.
	Transaction bool `uvalue:"transaction,omitempty"`

	// Pretty requests pretty-printed JSON.
	Pretty bool `uvalue:"pretty,omitempty"`

	// Timings requests timing information.
	Timings bool `uvalue:"timings,omitempty"`

	// Queue requests that the statement be queued
	Queue bool `uvalue:"queue,omitempty"`

	// Wait requests that the system only respond once the statement has been committed.
	// This is ignored unless Queue is true. If Queue is not true, an Execute request
	// always waits until the request has been committed.
	Wait bool `uvalue:"wait,omitempty"`

	// Timeout after which if Wait is set, the system should respond with an error if
	// the request has not been persisted.
	Timeout time.Duration `uvalue:"timeout,omitempty"`
}

ExecuteOptions holds optional settings for /db/execute requests.

type ExecuteResponse

type ExecuteResponse struct {
	Results        []ExecuteResult `json:"results"`
	Time           float64         `json:"time,omitempty"`
	SequenceNumber int64           `json:"sequence_number,omitempty"`
}

ExecuteResponse represents the JSON returned by /db/execute.

func (*ExecuteResponse) HasError

func (er *ExecuteResponse) HasError() (bool, int, string)

HasError returns true if any of the results in the response contain an error. If an error is found, the index of the result and the error message are returned.

type ExecuteResult

type ExecuteResult struct {
	LastInsertID int64   `json:"last_insert_id"`
	RowsAffected int64   `json:"rows_affected"`
	Time         float64 `json:"time,omitempty"`
	Error        string  `json:"error,omitempty"`
}

ExecuteResult is an element of ExecuteResponse.Results.

type Host

type Host struct {
	URL     *url.URL
	Healthy bool
}

Host represents a URL and its health status.

type HostChecker

type HostChecker func(url *url.URL) bool

HostChecker is a function that takes a URL and returns true if the URL is healthy.

type LoadBalancer

type LoadBalancer interface {
	// Next returns the next URL to use for the request.
	Next() (*url.URL, error)
}

LoadBalancer is the interface load balancers must support.

type LoadOptions

type LoadOptions struct {
	// If set, instruct a Follower to return a redirect instead of forwarding.
	Redirect bool `uvalue:"redirect,omitempty"`
}

LoadOptions configures how to load data into the node.

type LoopbackBalancer

type LoopbackBalancer struct {
	// contains filtered or unexported fields
}

LoopbackBalancer takes a single address and always returns it when Next() is called. It performs no healthchecking.

func NewLoopbackBalancer

func NewLoopbackBalancer(address string) (*LoopbackBalancer, error)

NewLoopbackBalancer returns a new LoopbackBalancer.

func (*LoopbackBalancer) Next

func (lb *LoopbackBalancer) Next() (*url.URL, error)

Next returns the next address in the list of addresses.

type NodeOptions

type NodeOptions struct {
	Timeout   time.Duration `uvalue:"timeout,omitempty"`
	Pretty    bool          `uvalue:"pretty,omitempty"`
	NonVoters bool          `uvalue:"non_voters,omitempty"`
	Version   string        `uvalue:"ver,omitempty"`
}

NodeOptions holds optional settings for /nodes requests.

type QueryOptions

type QueryOptions struct {
	// Timeout is applied at the database level.
	Timeout time.Duration `uvalue:"timeout,omitempty"`

	// Pretty controls whether pretty-printed JSON should be returned.
	Pretty bool `uvalue:"pretty,omitempty"`

	// Timings controls whether the response should including timing information.
	Timings bool `uvalue:"timings,omitempty"`

	// Associative signals whether to request the "associative" form of results.
	Associative bool `uvalue:"associative,omitempty"`

	// BlobAsArray signals whether to request the BLOB data as arrays of byte values.
	BlobAsArray bool `uvalue:"blob_array,omitempty"`

	// Level controls the read consistency level for the query.
	Level               ReadConsistencyLevel `uvalue:"level,omitempty"`
	LinearizableTimeout time.Duration        `uvalue:"linearizable_timeout,omitempty"`
	Freshness           time.Duration        `uvalue:"freshness,omitempty"`
	FreshnessStrict     bool                 `uvalue:"freshness_strict,omitempty"`
}

QueryOptions holds optional settings for /db/query requests.

type QueryResponse

type QueryResponse struct {
	Results any     `json:"results"`
	Time    float64 `json:"time,omitempty"`
}

QueryResponse represents the JSON returned by /db/query in the default (non-associative) form.

func (*QueryResponse) GetQueryResults

func (qr *QueryResponse) GetQueryResults() []QueryResult

GetQueryResults returns the results as a slice of QueryResult. This can be convenient when the caller knows the type of the results in advance. If the results are not a slice of QueryResult, a panic will occur.

func (*QueryResponse) GetQueryResultsAssoc

func (qr *QueryResponse) GetQueryResultsAssoc() []QueryResultAssoc

GetQueryResultsAssoc returns the results as a slice of QueryResultAssoc. This can be convenient when the caller knows the type of the results in advance. If the results are not a slice of QueryResultAssoc, a panic will occur.

func (*QueryResponse) HasError

func (qr *QueryResponse) HasError() (bool, int, string)

HasError returns true if any of the results in the response contain an error. If an error is found, the index of the result and the error message are returned.

func (*QueryResponse) UnmarshalJSON

func (qr *QueryResponse) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for QueryResponse.

type QueryResult

type QueryResult struct {
	Columns []string `json:"columns"`
	Types   []string `json:"types"`
	Values  [][]any  `json:"values"`
	Time    float64  `json:"time,omitempty"`
	Error   string   `json:"error,omitempty"`
}

QueryResult is an element of QueryResponse.Results.

type QueryResultAssoc

type QueryResultAssoc struct {
	Types map[string]string `json:"types"`
	Rows  []map[string]any  `json:"rows"`
	Time  float64           `json:"time,omitempty"`
	Error string            `json:"error,omitempty"`
}

QueryResultAssoc is an element of QueryResponse.Results, but in an associative form.

type RandomBalancer

type RandomBalancer struct {
	// contains filtered or unexported fields
}

RandomBalancer takes a list of addresses and returns a random one from its healthy list when Next() is called. At the start all supplied addresses are considered healthy. If a client detects that an address is unhealthy, it can call MarkBad() to mark the address as unhealthy. The RandomBalancer will then periodically check the health of the address and mark it as healthy again if and when it becomes healthy.

func NewRandomBalancer

func NewRandomBalancer(urls []string, chckFn HostChecker, d time.Duration) (*RandomBalancer, error)

NewRandomBalancer returns a new RandomBalancer.

func (*RandomBalancer) Bad

func (rb *RandomBalancer) Bad() []*url.URL

Bad returns the slice of currently bad hosts.

func (*RandomBalancer) Close

func (rb *RandomBalancer) Close()

Close closes the RandomBalancer. A closed RandomBalancer should not be reused.

func (*RandomBalancer) Healthy

func (rb *RandomBalancer) Healthy() []*url.URL

Healthy returns the slice of currently healthy hosts.

func (*RandomBalancer) MarkBad

func (rb *RandomBalancer) MarkBad(u *url.URL)

MarkBad marks an address returned by Next() as bad. The RandomBalancer will not return this address until the RandomBalancer considers it healthy again.

func (*RandomBalancer) Next

func (rb *RandomBalancer) Next() (*url.URL, error)

Next returns a random address from the list of addresses it currently considers healthy.

type ReadConsistencyLevel

type ReadConsistencyLevel int

ReadConsistencyLevel indicates the Read Consistency level requested by the user, if any.

func (ReadConsistencyLevel) String

func (rcl ReadConsistencyLevel) String() string

String returns the string representation of a Read Consistency level.

type RequestOptions

type RequestOptions struct {
	// Transaction indicates whether statements should be enclosed in a transaction.
	Transaction bool `uvalue:"transaction,omitempty"`

	// Timeout is applied at the database level.
	Timeout     time.Duration `uvalue:"timeout,omitempty"`
	Pretty      bool          `uvalue:"pretty,omitempty"`
	Timings     bool          `uvalue:"timings,omitempty"`
	Associative bool          `uvalue:"associative,omitempty"`
	BlobAsArray bool          `uvalue:"blob_array,omitempty"`

	Level               ReadConsistencyLevel `uvalue:"level,omitempty"`
	LinearizableTimeout string               `uvalue:"linearizable_timeout,omitempty"`
	Freshness           string               `uvalue:"freshness,omitempty"`
	FreshnessStrict     bool                 `uvalue:"freshness_strict,omitempty"`
}

RequestOptions holds optional settings for /db/request requests.

type RequestResponse

type RequestResponse struct {
	Results any     `json:"results"`
	Time    float64 `json:"time,omitempty"`
}

RequestResponse represents the JSON returned by /db/request.

func (*RequestResponse) GetRequestResults

func (rr *RequestResponse) GetRequestResults() []RequestResult

GetRequestResults returns the results as a slice of RequestResult. This can be convenient when the caller does not know the type of the results in advance. If the results are not a slice of RequestResult, a panic will occur.

func (*RequestResponse) GetRequestResultsAssoc

func (rr *RequestResponse) GetRequestResultsAssoc() []RequestResultAssoc

GetRequestResultsAssoc returns the results as a slice of RequestResultAssoc. This can be convenient when the caller does not know the type of the results in advance. If the results are not a slice of RequestResultAssoc, a panic will occur.

func (*RequestResponse) HasError

func (rr *RequestResponse) HasError() (bool, int, string)

HasError returns true if any of the results in the response contain an error. If an error is found, the index of the result and the error message are returned.

func (*RequestResponse) UnmarshalJSON

func (qr *RequestResponse) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for RequestResponse.

type RequestResult

type RequestResult struct {
	// Same fields as QueryResult plus ExecuteResult fields.
	// If read-only, LastInsertID and RowsAffected would be empty;
	// if write-only, Columns and Values would be empty.
	Columns      []string `json:"columns"`
	Types        []string `json:"types"`
	Values       [][]any  `json:"values"`
	LastInsertID *int64   `json:"last_insert_id"`
	RowsAffected *int64   `json:"rows_affected"`
	Error        string   `json:"error,omitempty"`
	Time         float64  `json:"time,omitempty"`
}

RequestResult is an element of RequestResponse.Results. It may include either Query-like results, Execute-like results, or both.

type RequestResultAssoc

type RequestResultAssoc struct {
	Types        map[string]string `json:"types"`
	Rows         []map[string]any  `json:"rows"`
	LastInsertID *int64            `json:"last_insert_id"`
	RowsAffected *int64            `json:"rows_affected"`
	Error        string            `json:"error,omitempty"`
	Time         float64           `json:"time,omitempty"`
}

RequestResultAssoc is an element of RequestResponse.Results, but in an associative form. It may include Query-like results, Execute-like results, or both.

type SQLStatement

type SQLStatement struct {
	// SQL is the text of the SQL statement, for example "INSERT INTO foo VALUES(?)".
	SQL string

	// PositionalParams is a slice of values for placeholders (?), if used.
	PositionalParams []any

	// NamedParams is a map of parameter names to values, if using named placeholders.
	NamedParams map[string]any
}

SQLStatement represents a single SQL statement, possibly with parameters.

func NewSQLStatement

func NewSQLStatement(stmt string, args ...any) (*SQLStatement, error)

NewSQLStatement creates a new SQLStatement from a SQL string and optional parameters. The parameters can be either a map of named parameters, or a slice of positional parameters.

func (SQLStatement) MarshalJSON

func (s SQLStatement) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON representation so that SQL statements always appear as an array in the format rqlite expects.

func (*SQLStatement) UnmarshalJSON

func (s *SQLStatement) UnmarshalJSON(data []byte) error

UnmarshalJSON implements a custom JSON representation so that SQL statements always appear as an array in the format rqlite expects.

type SQLStatements

type SQLStatements []*SQLStatement

SQLStatements is a slice of SQLStatement.

func NewSQLStatementsFromStrings

func NewSQLStatementsFromStrings(stmts []string) SQLStatements

func (SQLStatements) MarshalJSON

func (sts SQLStatements) MarshalJSON() ([]byte, error)

MarshalJSON for SQLStatements produces a JSON array whose elements are each statement’s custom JSON form.

func (*SQLStatements) UnmarshalJSON

func (sts *SQLStatements) UnmarshalJSON(data []byte) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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