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-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.

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