Documentation
¶
Overview ¶
Package s3storage is a small, practical file-storage layer over S3 and S3-compatible services (MinIO, Cloudflare R2): upload with correct content-type, download, presign, public/CDN URLs and typed errors — the operations a web application actually needs, without learning the SDK surface.
Index ¶
- Variables
- type Object
- type Option
- type PresignedUpload
- type Store
- func (s *Store) Delete(ctx context.Context, key string) error
- func (s *Store) Download(ctx context.Context, key string) (io.ReadCloser, *Object, error)
- func (s *Store) Exists(ctx context.Context, key string) (bool, error)
- func (s *Store) List(ctx context.Context, prefix string) iter.Seq2[*Object, error]
- func (s *Store) PresignGet(ctx context.Context, key string, ttl time.Duration) (string, error)
- func (s *Store) PresignPut(ctx context.Context, key string, ttl time.Duration, opts ...UploadOption) (*PresignedUpload, error)
- func (s *Store) PublicURL(key string) string
- func (s *Store) Stat(ctx context.Context, key string) (*Object, error)
- func (s *Store) Upload(ctx context.Context, key string, r io.Reader, opts ...UploadOption) (*Object, error)
- type UploadOption
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotFound = errors.New("s3storage: object not found") ErrBucketNotFound = errors.New("s3storage: bucket not found") ErrAccessDenied = errors.New("s3storage: access denied") )
Sentinel errors for matching with errors.Is. The original SDK error stays in the chain for errors.As inspection.
Functions ¶
This section is empty.
Types ¶
type Object ¶
type Object struct {
Key string
Size int64
ContentType string
ETag string
LastModified time.Time
Metadata map[string]string
}
Object describes a stored file. Key is always the logical key (prefix stripped); ETag comes without surrounding quotes.
type Option ¶
type Option func(*Store)
Option configures a Store.
func WithBaseEndpoint ¶
WithBaseEndpoint points the client at an S3-compatible service (MinIO, Cloudflare R2). Usually combined with WithPathStyle for MinIO.
func WithKeyPrefix ¶
WithKeyPrefix prepends prefix/ to every key, transparently for the caller. Useful for tenant or environment separation inside one bucket.
func WithPathStyle ¶
func WithPathStyle() Option
WithPathStyle forces path-style addressing (endpoint/bucket/key instead of bucket.endpoint/key). Required by MinIO and most self-hosted services.
func WithPublicBaseURL ¶
WithPublicBaseURL makes PublicURL build links on a CDN or public domain instead of the bucket endpoint.
func WithUploadPartSize ¶
WithUploadPartSize sets the multipart chunk size (min 5MB per S3).
type PresignedUpload ¶
PresignedUpload is a time-limited direct-upload target. Header holds the signed headers (Cache-Control, x-amz-meta-*): the uploader must send them verbatim or S3 rejects the PUT with a signature mismatch.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps one bucket. It is safe for concurrent use; construct once and share. All keys are "logical": the optional key prefix is applied on the way in and stripped on the way out.
func New ¶
New builds a Store for the bucket on top of the given AWS config (config.LoadDefaultConfig covers profiles, roles and env vars).
func (*Store) Delete ¶
Delete removes the object. Deleting a missing key is not an error — S3 deletes are idempotent.
func (*Store) Download ¶
Download streams the object; the caller must Close the reader. The whole body is never held in memory.
func (*Store) List ¶
List iterates all objects under the prefix, paginating transparently:
for obj, err := range store.List(ctx, "invoices/") {
if err != nil { return err }
...
}
On error one (nil, err) pair is yielded and iteration stops.
func (*Store) PresignGet ¶
PresignGet returns a time-limited download URL for a private object. Signing is local, no network call happens.
func (*Store) PresignPut ¶
func (s *Store) PresignPut(ctx context.Context, key string, ttl time.Duration, opts ...UploadOption) (*PresignedUpload, error)
PresignPut returns a time-limited upload URL, typically handed to a browser for direct upload. Content-Type is deliberately NOT part of the signature (the AWS SDK strips it so clients can set their own); metadata and cache-control ARE signed and come back in Header.
func (*Store) PublicURL ¶
PublicURL returns the non-expiring URL of a key: the CDN base when configured, otherwise the bucket endpoint. It does not check existence and assumes the object is publicly readable.
func (*Store) Upload ¶
func (s *Store) Upload(ctx context.Context, key string, r io.Reader, opts ...UploadOption) (*Object, error)
Upload streams r to the bucket, switching to multipart automatically for large content — r is never buffered whole. Content type resolution: WithContentType > file extension > sniffing the first 512 bytes.
type UploadOption ¶
type UploadOption func(*uploadConfig)
UploadOption configures a single upload (or a presigned PUT, where each value becomes a signed header the uploader must send back).
func WithCacheControl ¶
func WithCacheControl(v string) UploadOption
WithCacheControl sets the Cache-Control header stored with the object.
func WithContentDisposition ¶
func WithContentDisposition(v string) UploadOption
WithContentDisposition sets the Content-Disposition header stored with the object (e.g. `attachment; filename="report.pdf"`).
func WithContentType ¶
func WithContentType(ct string) UploadOption
WithContentType skips detection and sets the value as-is.
func WithMetadata ¶
func WithMetadata(m map[string]string) UploadOption
WithMetadata attaches user metadata (x-amz-meta-*).