GoodMemGoodMem
How-To Guides

Download Original Files

Download stored documents, inspect their headers, and resume interrupted transfers.

Use GET /v1/memories/{id}/content to download the original bytes of a stored document. You need an API key with read access to the memory. Documents stored only through an external reference return 404; retrieve their originalContentRef from the memory metadata.

curl --fail --show-error \
  -H "x-api-key: $GOODMEM_API_KEY" \
  -H "Accept-Encoding: identity" \
  --dump-header document.headers \
  --output document.pdf \
  "$GOODMEM_URL/v1/memories/$MEMORY_ID/content"

The response uses the stored content type and includes an ETag identifying the source. A full, uncompressed response also includes its byte length and SHA-256 Digest.

Download with the CLI

goodmem memory get "$MEMORY_ID" --output document.pdf

The CLI streams the file and verifies its SHA-256. It downloads into a temporary file beside the destination, then replaces the destination after a successful transfer. Allow enough local disk space for the download alongside any existing file. Omit --output to stream to stdout, or use -O to choose the filename from the memory's metadata.

Upgrade the server before using this CLI download path: it requires the GetMemoryContent RPC. For resumable downloads or byte ranges, use the HTTP examples below.

Inspect headers without downloading

Use HEAD to get the download headers without reading the file's contents:

curl --head --fail \
  -H "x-api-key: $GOODMEM_API_KEY" \
  -H "Accept-Encoding: identity" \
  "$GOODMEM_URL/v1/memories/$MEMORY_ID/content"

Resume or read part of a file

GoodMem supports one byte range per request. For example, Range: bytes=1048576- starts at byte 1,048,576, and Range: bytes=-1024 reads the final 1,024 bytes. A successful range response returns 206 and Content-Range; an invalid or unsatisfiable range returns 416.

The first example saves the response headers in document.headers, even if the transfer is interrupted. To resume, send that response's ETag in If-Match. GoodMem checks it as part of the download request, preventing a changed document from being appended to the old file:

etag=$(awk 'tolower($1) == "etag:" {sub(/\r$/, "", $2); print $2}' document.headers)
test -n "$etag" || { echo "No saved ETag; restart the download." >&2; exit 1; }

curl --fail --show-error --continue-at - \
  -H "x-api-key: $GOODMEM_API_KEY" \
  -H "Accept-Encoding: identity" \
  -H "If-Match: $etag" \
  --output document.pdf \
  "$GOODMEM_URL/v1/memories/$MEMORY_ID/content"

If the server returns 412, restart using the first command to replace both the file and its saved headers. Do the same if you no longer have the original ETag.

Range responses use the original, uncompressed bytes. Full text-like responses can use gzip when requested; these are compressed during delivery and omit Content-Length. Treat a connection error as an incomplete transfer and retry or resume it.

Large files

GoodMem streams original-file downloads in bounded blocks. Range requests on uncompressed storage read only the selected interval, and downloads do not need a server scratch file. Each active download holds a database connection. GoodMem limits concurrent content requests to min(10, max(1, primary pool size - 3)). For example, a pool of 50 allows 10 downloads, and a pool of 10 allows 7. Pools of one or two connections allow one download. Other operations can use the entire pool; downloads do not reserve connections. When the download limit is reached, requests receive 429 with Retry-After and can be retried later.

Documents stored under the older compressed storage policy remain downloadable. Reading them can require whole-document decompression inside PostgreSQL even for a small range. The source-storage guidance describes the optional storage backfill.