Skip to main content

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

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-1.0.0.tar.gz (8.3 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-1.0.0-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for herfy_gcs-1.0.0.tar.gz
Algorithm Hash digest
SHA256 234bdffc00bf7f50501ebce45cb0ba4161d4c67f5ed14fadd1b35b301dc9b394
MD5 b977336367a766f07510ec10995cd720
BLAKE2b-256 69e793b706263d528182572978adf8b63d2a37ce7ce50eb523c26c2f9a5fcd3a

See more details on using hashes here.

Provenance

The following attestation bundles were made for herfy_gcs-1.0.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-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: herfy_gcs-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 10.2 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-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 70171336f184120508044d923820336eb2c823fbe0e462633a0b6d620a7c6da5
MD5 84d19c59a1854564f16fd2b9b58185b0
BLAKE2b-256 ff519d1d3c9b302df4c5084d77f5a4955b0ce7186e714282ae17cc749abb31df

See more details on using hashes here.

Provenance

The following attestation bundles were made for herfy_gcs-1.0.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.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

0.1.0

2 files

Supported by

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