CodamAIDocs
Topicdone

Downloading

How GET /{id}/file works, why the token is in the URL here, and which permissions and limits apply.

Variants
regular file model: GET /{id}/filesingleton: GET /fileaccess_token in the URLchecks: token, read, download roleresponse headers

What this is about

You read the record of a file model like any object. You fetch the content with an endpoint of its own:

Request
GET /api/rest/fileasset/f1…/file?access_token=eyJhbGciOi…
Response
200
Content-Type: application/pdf
Content-Disposition: inline; filename=Contract.pdf
Cache-Control: no-store

…bytes of the file…

What is special: the token is in the URL, in the parameter access_token, not in the Authorization header.

Why the token is in the URL

A link <a href>, an image <img src> or a PDF viewer in the browser fetch an address by themselves. They cannot send an Authorization header. So that such links work, the download endpoint takes the token as a parameter, and only that way: without access_token the request is rejected, even if a header is present.

sequenceDiagram
    participant U as User
    participant B as Browser
    participant D as CDMS
    participant F as File storage
    U->>B: clicks on "Contract.pdf"
    B->>D: GET /fileasset/f1…/file?access_token=…
    D->>D: check token (tenant served?)
    D->>D: read record: read role, visibility
    D->>D: check download role
    D->>F: read content
    F-->>D: bytes
    D-->>B: 200, Content-Type from mimeType
    B-->>U: shows the file or saves it

The checks

GET /fileasset/{id}/file
  1. CIAS
    Token
    Is the token from access_token valid, is its tenant served, and does it name a tenant at all in MULTI?
    ↳ no 403 with the key from CIAS, without a tenant in MULTI cias.authentication.tenant-required as in the filter chain; an unreadable token counts as anonymous and fails at the next station
  2. CDMS
    Read record
    Read role of the model and visibility of the row, as with POST /read/{id}
    ↳ no 403 without read role, 404 if invisible or not present
  3. CDMS
    Download role
    Do you have the download role of the model?
    ↳ no rejected
  4. File storage
    Content
    Is the content under the fileId, and is it readable?
    ↳ no file-not-found or file-not-readable
  5. 200 with the bytes

The response

HeaderValueEffect
Content-TypemimeType of the recordthe browser knows how to display the file
Content-Dispositioninline; filename=<name>the browser shows the file if it can, and suggests the name when saving
Cache-Controlno-storebrowsers and proxies do not keep the file in their cache

If the browser should always save the file instead of showing it, set the HTML attribute download on the link: <a href="…/file?access_token=…" download>.

Variants

How downloading works

When: GET {basis}/{id}/file?access_token=…

As above: all checks, response with Content-Type, Content-Disposition and Cache-Control.

When: GET {basis}/file?access_token=…, without id

The server finds the one object itself. If there is none yet, you get 404 file-not-found. Only the download role is checked, no read role is needed here. The response contains only the bytes as application/octet-stream, without file name and without file type.

Result: See Singletons.

When: The file hangs on another object, such as Company.logo.

Read the parent with the id of the child, for example "response": ["+", {"field": "logo", "response": ["id", "name"]}], and then fetch the file through the endpoint of the file model: GET /company/logo/{logoId}/file.

The endpoint exists as soon as the file model has the endpoint DOWNLOAD or READ. See Which endpoints a model has.

Pitfalls

What comes next

Sources in the code and the knowledge base
  • CDMS/cdms-generator – ApiProcessor.getDownloadMethod, ApiSingletonProcessor.getDownloadMethod, AbstractProcessor.isDownloadExposed
  • CDMS/cdms-rest-api – QueryTokenAuthentication, AbstractRestApi.downloadFile, AbstractRestSingletonApi.downloadFile
  • CDMS/cdms-system-layer – AbstractLayer.downloadFile (downloadAccessAllowedByClass)
  • CDMS/cdms-localfs-storage – LocalFSFileController.getFile (file-not-found, file-not-readable); docs/04-file-operations.md
Search