Documentation
¶
Overview ¶
Package gostorage provides a unified, provider-agnostic client for object storage. It supports AWS S3, MinIO, Supabase Storage, Alibaba Cloud OSS and Google Cloud Storage through a single interface:
- presigned upload and download URLs (browser direct-to-storage uploads),
- public URLs,
- listing and sizing objects under a prefix (e.g. a sub-bucket),
- deleting objects.
Credentials are never exposed to the client; only presigned or public URLs are returned.
Index ¶
Examples ¶
Constants ¶
const ( // DefaultTimeout is the client-side HTTP timeout used for provider // REST/raw HTTP calls such as OSS listing or deletion. DefaultTimeout = 30 * time.Second // DefaultPresignUploadExpiry is the default lifetime of a presigned // upload URL. DefaultPresignUploadExpiry = 15 * time.Minute // DefaultPresignGetExpiry is the default lifetime of a presigned // download URL. DefaultPresignGetExpiry = 15 * time.Minute )
Default timeouts and presign expiries used when the caller does not provide its own values.
Variables ¶
This section is empty.
Functions ¶
func LocalSign ¶ added in v1.1.1
LocalSign signs a local filesystem object URL with an HMAC-SHA256 digest.
Secret, method, key, expires and contentType are all bound into the signature so that a signature issued for one operation cannot be reused for another (including a PUT upload vs a GET download) or after its expiry has passed. The key is normalized exactly as it is stored, and contentType is normalized (trimmed and lower-cased), so the exact same arguments must be fed to LocalVerify or to the local GetPresignedUploadURL/GetPresignedGetURL implementations.
func LocalVerify ¶ added in v1.1.1
LocalVerify reports whether signature is a valid LocalSign digest for the given secret, method, key, expires and contentType. The comparison is constant-time so that signature values cannot be guessed by timing.
Expiry is intentionally not enforced here; it is the caller's job to decide how to treat a signature whose expires timestamp is already in the past.
Types ¶
type Client ¶
type Client interface {
// GetPresignedUploadURL returns a URL that lets a client upload the
// object at key without holding credentials, using an HTTP PUT request.
//
// For S3, MinIO and OSS a signed PUT URL for bucket/key is returned.
// contentType, when non-empty, is bound into the signature so the
// provider rejects uploads with a mismatched Content-Type; expiry is
// honored with one-second precision.
//
// For Supabase a server-side signed upload URL is returned instead.
// contentType is not part of the Supabase contract and its lifetime is
// governed by the provider, so expiry is ignored; keep the default
// (DefaultPresignUploadExpiry) so the browser has enough time to
// complete the PUT.
//
// Returns an error only when the provider rejects the signing
// operation, e.g. because the credentials are invalid.
GetPresignedUploadURL(key, contentType string, expiry time.Duration) (string, error)
// GetPresignedGetURL returns a signed URL that lets a client download
// the object at key without holding credentials.
//
// For S3, MinIO and OSS the returned URL is an HTTP GET request for
// bucket/key. For Supabase a signed download URL is returned instead;
// expiry is honored at one-second precision. For local, when
// Config.PublicBaseURL is set, an expiring GET URL under that base is
// returned; otherwise the on-disk path is returned (see GetPresignedUploadURL).
//
// Returns an error only when the provider rejects the signing
// operation.
GetPresignedGetURL(key string, expiry time.Duration) (string, error)
// GetPublicURL returns the public (unsigned) URL of the object at key.
//
// The object must be publicly readable through the provider's bucket
// policy; no signing or credentials are involved and this method never
// returns an error. An empty key yields a URL ending with the bucket
// path. For local, when Config.PublicBaseURL is set, the returned URL is
// an unsigned URL under that base; otherwise the on-disk path is
// returned.
GetPublicURL(key string) string
// GetSize returns the total size in bytes of every object stored under
// prefix. Prefixes that expand to nothing (or to only empty objects)
// return zero. The error is non-nil only when listing the provider
// fails, in which case the returned size may be incomplete.
GetSize(prefix string) (int64, error)
// ListObjects returns the objects stored under prefix, listed
// recursively. Keys are relative to the bucket and their order is
// unspecified. The error is non-nil only when listing the provider
// fails, in which case the returned slice may be incomplete.
ListObjects(prefix string) ([]ObjectInfo, error)
// DeleteObject permanently removes the object at key. Providers treat
// deleting an already-missing object as a no-op or an error depending
// on their semantics; the error is non-nil only when the deletion could
// not be performed.
DeleteObject(key string) error
// Type returns the full storage type as configured, e.g. "acme-s3".
Type() string
// Name returns the logical storage name as configured.
Name() string
// Kind returns the resolved provider kind.
Kind() Kind
}
Client is the unified interface implemented by every storage provider.
Every URL produced by this interface is self-contained: the signature or public access is embedded in it, so any HTTP client (such as a browser) can upload or download objects without ever holding the provider credentials. All methods are safe for concurrent use by multiple goroutines.
func New ¶
New builds a Client for the given config, routing to the provider matching the resolved Kind.
Example ¶
ExampleNew demonstrates the full lifecycle of a storage client: a presigned upload URL, a presigned download URL and the public URL for one object key. It uses the local MinIO from docker-compose.yml (see the README). Presigning is computed locally, so the example runs without a running server; the bucket only matters for real uploads/downloads.
client, err := New(Config{
Kind: KindMinio, // docker-compose MinIO (see README)
Name: "chum-bucket",
Endpoint: "http://localhost:9000",
AccessKey: "minioadmin",
SecretKey: "minioadmin",
})
if err != nil {
panic(err)
}
key := "krabby-patty/reports/2026-09-11.pdf"
// Presigned URLs are signed per request; only the public URL is stable.
uploadURL, err := client.GetPresignedUploadURL(key, "application/pdf", DefaultPresignUploadExpiry)
if err != nil {
panic(err)
}
fmt.Println(uploadURL != "")
downloadURL, err := client.GetPresignedGetURL(key, DefaultPresignGetExpiry)
if err != nil {
panic(err)
}
fmt.Println(downloadURL != "")
fmt.Println("public URL:", client.GetPublicURL(key))
Output: true true public URL: http://localhost:9000/chum-bucket/krabby-patty/reports/2026-09-11.pdf
func NewLocal ¶ added in v1.1.0
NewLocal builds a local filesystem storage client. cfg.Kind is forced to KindLocal.
func NewSupabase ¶
NewSupabase builds a Supabase Storage client. cfg.Kind is forced to KindSupabase.
type Config ¶
type Config struct {
// Type is the fully qualified type such as "acme-s3".
// The qualifier before the first "-" is arbitrary and is stripped when
// Kind is not set; a plain kind such as "s3" is also accepted.
Type string
// Kind is the raw provider kind: one of KindS3, KindMinio, KindSupabase,
// KindOSS or KindGCS. Derived from Type when empty.
Kind Kind
// Name is the user-facing storage name (e.g. "chum-bucket").
Name string
// Bucket is the bucket inside the provider. Defaults to Name when empty.
Bucket string
// Endpoint is the provider endpoint. It may include a scheme
// (http:// or https://); otherwise TLS is assumed.
Endpoint string
// Region is the provider region. For Supabase it holds the project
// reference id that maps to "<ref>.supabase.co".
Region string
// AccessKey is the provider access key. For Supabase it is the anon or
// service_role API key used as the Bearer token.
AccessKey string
// SecretKey is the provider secret key. For local storage it is the HMAC
// key used to sign local presigned URLs (see PublicBaseURL).
SecretKey string
// PublicBaseURL is the externally reachable HTTP base under which local
// filesystem objects are served and uploaded, e.g.
// "https://files.example.com/storages".
//
// It is only used by the local provider. When set, GetPresignedUploadURL
// and GetPresignedGetURL return expiring URLs into PublicBaseURL signed
// with LocalSign, and GetPublicURL returns an unsigned URL under the same
// base; otherwise all three return the absolute on-disk path of the
// object, preserving the legacy behavior.
PublicBaseURL string
// Context is the base context used for storage operations. Defaults to
// context.Background() when nil.
Context context.Context
// Timeout bounds HTTP requests made directly by this library (OSS raw
// calls). Defaults to DefaultTimeout.
Timeout time.Duration
}
Config describes a single storage backend. Kind is derived from Type when empty and Bucket defaults to Name.
type Kind ¶
type Kind string
Kind identifies a supported storage provider.
const ( // KindS3 is Amazon Web Services S3 or any other S3-compatible endpoint // using virtual-hosted style URLs (e.g. Cloudflare R2, DigitalOcean // Spaces). KindS3 Kind = "s3" // KindMinio is MinIO, typically reachable over a raw host:port // endpoint using path-style URLs. KindMinio Kind = "minio" // KindSupabase is Supabase Storage, accessed through its REST API. KindSupabase Kind = "supabase" // KindOSS is Alibaba Cloud Object Storage Service. KindOSS Kind = "oss" // KindGCS is Google Cloud Storage. KindGCS Kind = "gcs" // KindLocal is local filesystem storage using file:// URLs. KindLocal Kind = "local" )
func ParseType ¶
ParseType splits a storage type into its provider qualifier and raw kind.
The type is split on the first "-": anything before it is treated as an arbitrary provider qualifier and the remainder must be a supported kind (e.g. "acme-s3", "acme-oss", "acme-minio"). A bare kind such as "s3" is returned with an empty qualifier. Parsing is case insensitive.
func SupportedKinds ¶
func SupportedKinds() []Kind
SupportedKinds returns all storage kinds supported by this library.