Skip to main content

GCS storage SDK for Herfy applications — upload/download via Control Center

Project description

herfy-gcs

GCS storage SDK for Herfy applications.
Files are uploaded to and downloaded from Google Cloud Storage through the Herfy Control Center — apps never handle raw GCS credentials directly.

How it works

App ──(client_id + secret)──► Control Center ──(service account)──► GCS bucket
  1. Your app registered with the Control Center and received a client_id + client_secret.
  2. The SDK exchanges those credentials for a short-lived CC access token (OAuth2 client credentials flow).
  3. Upload / download requests go to the CC storage API; the CC proxies them to GCS under its own service account.
  4. The CC enforces per-app bucket/prefix scoping — your app can only touch its own folder.

Installation

# From PyPI (once published)
pip install herfy-gcs==0.1.0

# Local editable install (monorepo / during development)
pip install -e /path/to/herfy-shared/herfy-gcs

Quick start

Environment variables

CONTROL_CENTER_URL=https://controlcenter-xxx.run.app
AUTH_CLIENT_ID=app_your_client_id        # from CC registration
AUTH_CLIENT_SECRET=your_client_secret    # from CC registration

Optional overrides:

Variable Default Description
GCS_STORAGE_API_PATH /api/storage CC storage endpoint prefix
GCS_TOKEN_CACHE_TTL 240 Seconds to cache the CC token
GCS_UPLOAD_TIMEOUT 120 HTTP timeout for upload/download (seconds)
GCS_REQUEST_TIMEOUT 15 HTTP timeout for metadata requests (seconds)

Sync client (default — works in FastAPI sync endpoints)

from herfy_gcs import HerfyGCSClient

client = HerfyGCSClient.from_env()

# Upload a file
with open("deposit.pdf", "rb") as f:
    result = client.upload(
        content=f,
        filename="deposit.pdf",
        content_type="application/pdf",
        folder="daily-cash/2025",
    )

print(result.file_ref)   # store this in your database

# Get a signed download URL (valid for 1 hour)
url = client.get_download_url(result.file_ref, expires_in=3600)

# Download raw bytes
data = client.download(result.file_ref)

# Resolve any existing reference (GCS URL or CC ref) to a usable URL
url = client.resolve_url(existing_db_ref)

# Delete a file
client.delete(result.file_ref)

Async client (for async FastAPI endpoints)

from herfy_gcs import AsyncHerfyGCSClient

client = AsyncHerfyGCSClient.from_env()

result = await client.upload(content=pdf_bytes, filename="doc.pdf", folder="daily-cash")
url = await client.get_download_url(result.file_ref)
data = await client.download(result.file_ref)

Explicit credentials (no env vars)

client = HerfyGCSClient.from_credentials(
    client_id="app_7c144431f50c",
    client_secret="your-secret",
    control_center_url="https://controlcenter-xxx.run.app",
)

FastAPI dependency example

from functools import lru_cache
from fastapi import Depends
from herfy_gcs import HerfyGCSClient

@lru_cache(maxsize=1)
def get_gcs_client() -> HerfyGCSClient:
    return HerfyGCSClient.from_env()

@app.post("/upload")
async def upload_file(
    file: UploadFile,
    gcs: HerfyGCSClient = Depends(get_gcs_client),
):
    result = gcs.upload(
        content=await file.read(),
        filename=file.filename,
        content_type=file.content_type or "application/octet-stream",
        folder="daily-cash",
    )
    return {"file_ref": result.file_ref, "url": result.url}

Control Center storage API

The CC must expose these endpoints (authenticated with a CC bearer token):

Method Path Description
POST /api/storage/upload Multipart file upload
POST /api/storage/signed-url Generate a signed download URL
GET /api/storage/file Get file metadata (?ref=<ref>)
GET /api/storage/download Stream file bytes (?ref=<ref>)
DELETE /api/storage/file Delete a file (?ref=<ref>)

Upload request

POST /api/storage/upload
Authorization: Bearer <cc_token>
Content-Type: multipart/form-data

file=<bytes>
filename=deposit.pdf
folder=daily-cash/2025

Response 200 OK:

{
  "file_ref": "cc:bucket_herfy_datacloud/daily-cash/2025/deposit.pdf",
  "url": "https://storage.googleapis.com/bucket_herfy_datacloud/...",
  "filename": "deposit.pdf",
  "content_type": "application/pdf",
  "size": 204800,
  "folder": "daily-cash/2025"
}

Signed URL request

POST /api/storage/signed-url
Authorization: Bearer <cc_token>
Content-Type: application/json

{"file_ref": "cc:...", "expires_in": 3600}

Response 200 OK:

{"url": "https://storage.googleapis.com/...?X-Goog-Signature=...", "file_ref": "cc:...", "expires_in": 3600}

Error handling

from herfy_gcs import HerfyGCSClient, UploadError, AuthError, FileNotFoundError, GCSError

client = HerfyGCSClient.from_env()

try:
    result = client.upload(content=data, filename="doc.pdf")
except AuthError as e:
    # Invalid client_id/secret or CC unreachable
    print(f"Auth failed: {e.message}")
except UploadError as e:
    print(f"Upload failed (HTTP {e.status_code}): {e.message}")
except GCSError as e:
    print(f"Storage error: {e.message}")

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

herfy_gcs-0.1.0.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

herfy_gcs-0.1.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file herfy_gcs-0.1.0.tar.gz.

File metadata

  • Download URL: herfy_gcs-0.1.0.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for herfy_gcs-0.1.0.tar.gz
Algorithm Hash digest
SHA256 96ade3fde0634c7e14efd67bac3be9d9ca28e16967262421b2689791cd5af3cd
MD5 498a8957afe36c77ea5e358192f84a64
BLAKE2b-256 f21bce8a8d4a2830598324927cff8f1cb357f3013b8f94e641f16abe86614157

See more details on using hashes here.

Provenance

The following attestation bundles were made for herfy_gcs-0.1.0.tar.gz:

Publisher: publish-gcs-sdk.yml on Herfy-Food-Services/herfy-shared-library

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file herfy_gcs-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: herfy_gcs-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for herfy_gcs-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af524800dafb773444c451b3f28a15949d9e2d85d1e8abc51e01733f241ab1ef
MD5 db80bddce908c4954697a5f1ef765a62
BLAKE2b-256 a8ac535f1b4def5ca6ff9ab5a6d32cfc92698fa1a27b23bd0f49658b268991dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for herfy_gcs-0.1.0-py3-none-any.whl:

Publisher: publish-gcs-sdk.yml on Herfy-Food-Services/herfy-shared-library

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page