GStorage SDKs — install & use
Client libraries that wrap the GStorage HTTP API (/api/v1) so a service stores
and retrieves files in one call — auth + token refresh, request building, resumable
upload/download, dataset publishing, and search. They live in this repository
under sdk/ and are published to the GitLab Package Registry of the
GStorage project (git.esempla.systems/govtech/gstack/paas_gstorage).
| SDK | Language | Package | Registry | State |
|---|---|---|---|---|
| Java | Java 17+ | md.gov.gstorage:gstorage-sdk-java | GitLab Maven | ✅ built + published |
| Node | Node 18+ | @gstack/gstorage-sdk | GitLab npm | ✅ built + published |
| PHP | PHP 8.1+ | gstack/gstorage-sdk | GitLab Composer | 🟡 designed (scaffold, not published) |
The SDKs are thin wrappers over the documented HTTP API — anything an SDK does can
be done with a plain request. A runnable Node example is in
examples/node-demo.
Authentication (both modes)
Section titled “Authentication (both modes)”GStorage /api/v1 requires auth. Two mechanisms, both supported by every SDK:
- API key (standalone, no Keycloak). A local
ApiClientrow (tip=API_KEY) with a hashed secret. Sent asX-Api-Key: <key>. Best for a bolt-on microservice that doesn’t run Keycloak. - Keycloak client-credentials (gStack infra). A confidential client
(
gstorage-ingest) → bearer token with scopesstorage:read|write|admin+tenantclaim. The SDK acquires and refreshes it automatically.
Your tenant must match the token/key’s tenant, or the call gets 403. Scopes:
storage:read (download/search), storage:write (upload/publish), storage:admin
(buckets/datasets/grants).
Java SDK
Section titled “Java SDK”<!-- pom.xml — point at the GitLab Maven registry (project id filled after creation) --><repository> <id>gitlab-gstorage</id> <url>https://git.esempla.systems/api/v4/projects/<PROJECT_ID>/packages/maven</url></repository>
<dependency> <groupId>md.gov.gstorage</groupId> <artifactId>gstorage-sdk-java</artifactId> <version>0.1.0</version></dependency>GStorageClient gs = GStorageClient.builder() .baseUrl("https://gstorage.gstack.esempla.systems") .tenant("demo") // API key (standalone): .apiKey(System.getenv("GSTORAGE_API_KEY")) // …or Keycloak client-credentials (infra): // .tokenSupplier(new KeycloakTokenSupplier( // "https://sso.gstack.esempla.systems/realms/gstorage", "gstorage-ingest", secret)) .build();
// simple uploadStoredObject obj = gs.put("rapoarte", "2026/q1.csv", Path.of("q1.csv"));
// resumable upload (auto-continues on retry)gs.putResumable("rapoarte", "2026/big.zip", Path.of("big.zip"), 8 * 1024 * 1024); // 8MB parts
// download (range-resumable)gs.getToFile("rapoarte", "2026/q1.csv", Path.of("out.csv"));
// publish an open-data datasetDataset ds = gs.datasets().create("Buget 2026", "finante-org", NivelAcces.PUBLIC);gs.datasets().addResource(ds.id(), "q1.csv", FormatResursa.CSV, obj.id());
// search inside file contentsSearchPage page = gs.search("subvenții agricultură", Map.of("grup", "agricultura"));
// pre-signed share link (public objects)URI link = gs.presignedUrl("rapoarte", "2026/q1.csv", Duration.ofHours(1));put* throw GStorageException; tryPut(...) is best-effort (never throws) for
hot paths. Full details: sdk/java/README.md.
Node SDK
Section titled “Node SDK”# .npmrc — GitLab npm registry@gstack:registry=https://git.esempla.systems/api/v4/projects/<PROJECT_ID>/packages/npm///git.esempla.systems/api/v4/projects/<PROJECT_ID>/packages/npm/:_authToken=${GITLAB_TOKEN}npm install @gstack/gstorage-sdkconst { GStorageClient, keycloakTokenProvider } = require('@gstack/gstorage-sdk');
const gs = new GStorageClient({ baseUrl: 'https://gstorage.gstack.esempla.systems', tenant: 'demo', apiKey: process.env.GSTORAGE_API_KEY, // standalone // …or infra: // tokenProvider: keycloakTokenProvider({ // issuer: 'https://sso.gstack.esempla.systems/realms/gstorage', // clientId: 'gstorage-ingest', clientSecret: process.env.GSTORAGE_CLIENT_SECRET }),});
// resumable upload — resumes from the last acked part if the connection dropsconst obj = await gs.putResumable('rapoarte', '2026/big.zip', './big.zip', { partSize: 8 << 20 });
// range-resumable downloadawait gs.getToFile('rapoarte', '2026/q1.csv', './out.csv');
// publish dataset + resourceconst ds = await gs.datasets.create({ titlu: 'Buget 2026', organizatie: 'finante-org', nivelAcces: 'PUBLIC' });await gs.datasets.addResource(ds.id, { denumire: 'q1.csv', format: 'CSV', obiectId: obj.id });
// full-text search inside filesconst page = await gs.search('subvenții agricultură', { grup: 'agricultura' });put(...) throws; tryPut(...) is best-effort. Runnable example:
examples/node-demo. Full details:
sdk/js/README.md.
PHP SDK (designed)
Section titled “PHP SDK (designed)”{ "repositories": [ { "type": "composer", "url": "https://git.esempla.systems/api/v4/group/1087/-/packages/composer/packages.json" } ], "require": { "gstack/gstorage-sdk": "^0.1" }}$gs = new Gstack\GStorage\Client( baseUrl: 'https://gstorage.gstack.esempla.systems', tenant: 'demo', apiKey: getenv('GSTORAGE_API_KEY'));
$obj = $gs->put('rapoarte', '2026/q1.csv', '/path/q1.csv');$gs->datasets()->addResource($datasetId, 'q1.csv', 'CSV', $obj->id);$page = $gs->search('subvenții agricultură', ['grup' => 'agricultura']);Scaffolded + documented, not yet published (same state as glog’s PHP SDK).
Common notes
Section titled “Common notes”- Resumable is the headline.
putResumablesplits into parts (default 8 MB), tracks aTransferSessionserver-side, and on retry queries progress and continues from the last acknowledged part.getToFileuses HTTPRangeto resume a partial download. Integrity is verified with sha-256 on completion. - Two faces, one client. The same client does raw object storage and
open-data catalog publishing (
gs.datasets()/gs.buckets()). - Best-effort variants (
tryPut/tryAudit-style) never throw — use them on hot paths so storage can’t break business logic. - Defaults filled for you:
tenant,contentType, part size, andeventTimestampare set from client config / detected if omitted. - Auth required: tokenless/keyless requests get 401; wrong tenant → 403;
insufficient scope → 403 (e.g. a
storage:write-only client reading).