client

package
v0.0.0-...-1eb71c3 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultPageSize = 100

DefaultPageSize is the page size every list walk uses unless told otherwise.

View Source
const ResponseFormat = "1.8.1"

ResponseFormat pins the API response shape the CLI is written against.

Hard-coded: it tracks the API version the CLI was generated for, not the CLI's own version, so it must not be wired to sdk.version.

Variables

View Source
var ExecutableName = "appwrite"

ExecutableName is the CLI's own name, for messages that name a command.

A package variable for the same reason RequestLog is one: internal/app owns the name, and app reaches this package through internal/sdk, so importing it would be a cycle. root.go sets it during start-up; the default is only what a test that never sets it reads.

View Source
var RequestLog func(format string, arguments ...any)

RequestLog receives one line per HTTP request when --verbose is on.

A package variable rather than a field on Client because clients are built in a dozen places and diagnostics should not have to be threaded through every one of them. Set once during start-up, before any request is made, and only read afterwards -- concurrent requests read it, none of them write it.

Functions

func EncodeQueries

func EncodeQueries(queries []string) string

EncodeQueries renders query strings as the API expects them.

`queries[0]=`, indexed -- NOT `queries[]=`. Both happen to work on the list endpoints, but the indexed form is what the request trace is pinned to, so the wire has to match too. Found by diffing traces on a command whose config output was already identical.

func NewHTTPClient

func NewHTTPClient(selfSigned bool) *http.Client

NewHTTPClient returns the HTTP policy shared by the CLI's direct requests and its generated SDK-backed service commands.

A whole-request deadline makes a slow upload fail even while it is still making progress. The transport instead bounds the individual connection and response-header phases. Self-signed verification is configured before any caller wraps the transport, because the generated SDK cannot see through a recording RoundTripper to change it later.

func Paginate

func Paginate(list Lister, wrapper string, queries []string, pageSize int) ([]any, int64, error)

Paginate walks a list endpoint until every row has been read.

wrapper names the array in the response -- "functions", "rows" and so on.

Two conditions stop the walk, and both are needed. An empty page stops it because a server that reports a stale total would otherwise loop forever; reaching the total stops it because a full final page would otherwise cost one extra request.

func PaginateInto

func PaginateInto(list Lister, wrapper string, queries []string, pageSize int) ([]*jsonx.Object, int64, error)

PaginateInto walks a list endpoint and returns the rows as objects.

Anything that is not an object is dropped rather than erroring: a list endpoint returns objects, and refusing to continue because one entry is malformed would fail a pull over a single bad row.

Types

type APIError

type APIError struct {
	Status           int
	Code             int    `json:"code"`
	Message          string `json:"message"`
	Type             string `json:"type"`
	OAuthError       string `json:"error"`
	OAuthDescription string `json:"error_description"`
}

APIError is a non-2xx response from the API. OAuthError and OAuthDescription cover RFC 6749 token endpoint failures, whose shape differs from the Appwrite API's code/message/type envelope.

func (*APIError) Error

func (e *APIError) Error() string

Error is what the user reads. The API's human-readable wording wins over its machine-readable error identifier.

type Client

type Client struct {
	Endpoint string
	HTTP     *http.Client

	SDKVersion string
	// contains filtered or unexported fields
}

Client is a thin HTTP client for the Appwrite API.

One client is shared across concurrent requests -- `push` runs deploy.UploadConcurrency chunk uploads through a single instance -- and every response can carry a Set-Cookie. The two cookie fields are the only mutable state, so one mutex covers them both.

func New

func New(endpoint, sdkVersion string) *Client

func (*Client) Call

func (c *Client) Call(method, path string, body any, out any) error

Call performs a request and decodes the JSON response into out.

out may be nil for endpoints whose body is not needed. Numbers decode as json.Number so large integers survive.

func (*Client) Clone

func (c *Client) Clone() *Client

Clone returns a copy with its own header map, so that scoping one call to an organization does not scope the next unrelated one.

Field by field rather than `copied := *c`, which would copy the mutex -- vet rejects it, and it would snapshot the cookies without holding the lock.

func (*Client) Download

func (c *Client) Download(path string) ([]byte, error)

Download fetches a path and returns the raw body.

Separate from Call because a deployment archive is not JSON, and decoding a gzip stream as JSON fails with a message about the first byte rather than about the archive.

func (*Client) List

func (c *Client) List(path, wrapper string, queries []string) ([]*jsonx.Object, error)

List walks a list endpoint through this client and returns its rows.

wrapper names the array in the response -- "functions", "rows" and so on. queries are the caller's own filters; the walk adds its own limit and offset per page. Page size is DefaultPageSize, which is the only size any caller has ever wanted.

func (*Client) SessionCookie

func (c *Client) SessionCookie() string

SessionCookie is the console session cookie the server last set.

An accessor rather than a field because reading it unsynchronised while an upload is in flight is a data race.

func (*Client) SetBearer

func (c *Client) SetBearer(token string) *Client

SetBearer authenticates with an OAuth2 access token.

func (*Client) SetCookie

func (c *Client) SetCookie(cookie string) *Client

SetCookie authenticates with a legacy session cookie.

func (*Client) SetHeader

func (c *Client) SetHeader(name, value string) *Client

SetHeader sets one header.

func (*Client) SetJWT

func (c *Client) SetJWT(jwt string) *Client

SetJWT authenticates with a JWT.

Deliberately unreachable for now: it completes the client setter surface, and the only caller will be the JwtManager that `run` still lacks.

func (*Client) SetKey

func (c *Client) SetKey(key string) *Client

SetKey authenticates with an API key.

func (*Client) SetLocale

func (c *Client) SetLocale(locale string) *Client

SetLocale sets the response locale.

func (*Client) SetMode

func (c *Client) SetMode(mode string) *Client

SetMode selects admin or default scope resolution.

func (*Client) SetOrganization

func (c *Client) SetOrganization(id string) *Client

SetOrganization names the organization for endpoints that take no ID in the path.

func (*Client) SetProject

func (c *Client) SetProject(project string) *Client

SetProject sets the project the request acts on.

func (*Client) SetSelfSigned

func (c *Client) SetSelfSigned(selfSigned bool) *Client

SetSelfSigned accepts a self-signed TLS certificate.

Both the transport and the http.Client are copies, never the shared default and never mutated in place: Clone copies the *http.Client by pointer, so mutating either would disable certificate verification for every clone and sibling -- including calls to Appwrite Cloud this client never made.

func (*Client) Upload

func (c *Client) Upload(part UploadPart, out any) error

Upload POSTs one multipart part and decodes the JSON response into out.

The body is assembled as three readers -- the form prefix, the file content, the closing boundary -- so its exact length is known without holding it. Content-Length matters here: without it Go falls back to chunked transfer-encoding, and the API sizes an upload from the header.

func (*Client) WithoutResponseFormat

func (c *Client) WithoutResponseFormat() *Client

WithoutResponseFormat drops the x-appwrite-response-format header, which asks the API for that version's response shape: the console routes answer it with a legacy flat project instead of the `services`/`protocols`/`authMethods` arrays the config is built from. This reproduces what the console SDK sends.

type FormField

type FormField struct {
	Name  string
	Value string
}

FormField is one text field of a multipart upload.

Ordered rather than a map: the request body is what a recorded trace compares, and Go map iteration would reorder the parts on every run.

type Lister

type Lister func(queries []string) (*jsonx.Object, error)

Lister fetches one page. queries are already-encoded query strings.

type Page

type Page struct {
	// Items are the rows under the wrapper key.
	Items []any
	// Total is the server's count of matching rows.
	Total int64
}

Page is one response from a list endpoint.

type UploadPart

type UploadPart struct {
	Path   string
	Fields []FormField
	// FileField is the form field the file is sent under, `code` for a
	// deployment.
	FileField     string
	FileName      string
	ContentType   string
	Content       io.Reader
	ContentLength int64
	// Range is the content-range header. Empty for an upload that fits in one
	// request, which the API answers without minting an upload id.
	Range string
	// UploadID pins this part to the upload the first chunk created.
	UploadID string
}

UploadPart is one multipart request of a chunked upload.

Content is read as the request body rather than buffered, so the caller decides how much of a file is in memory at once -- for a deployment archive that is a section reader over the file and the answer is "none of it".

Jump to

Keyboard shortcuts

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