ps-shin
Back to projects
2026·Active

fileservice

Storage-agnostic object storage library for Go — one interface, multiple backends (memory, S3-compatible).

GoS3AWS SDKMinIO

Why this exists

Every backend project I've worked on has eventually needed object storage — avatars, uploads, generated reports, exports. Each time it gets re-implemented as scattered S3 calls bolted into business code. fileservice is the library I want to drop into every new project so this layer is solved once, properly.

What it does

Defines a single Storage interface and ships pluggable backends behind it:

import (
    fs "github.com/PS-safe/fileservice"
    "github.com/PS-safe/fileservice/memory"
)

store := memory.New()
obj, _ := store.Put(ctx, "avatar.png", reader, fs.PutOptions{
    ContentType: "image/png",
})

Operations: Put, Get, Stat, Delete, PresignGet, PresignPut.

Backends

| Backend | Status | Use for | |---|---|---| | memory | Complete | tests, local dev | | s3 | Stub | AWS S3, Cloudflare R2, MinIO |

Design decisions worth noting

  • Streaming, not bytes. Put takes an io.Reader, Get returns an io.ReadCloser. Large files never have to fit in memory.
  • Contract tests, not per-backend tests. A single RunContract(t, newStore) function exercises every method; new backends just call it.
  • Sentinel errors with errors.Is. ErrNotFound, ErrInvalidKey — checked semantically, not by string matching.
  • No global state. Each backend is constructed explicitly with its config; library code is reentrant by default.

Future work

  • [ ] Wire up aws-sdk-go-v2 in the S3 backend
  • [ ] Multipart upload support
  • [ ] Per-tenant key prefixing (SaaS multi-tenancy)
  • [ ] OpenTelemetry metrics