skip to main content

Working with Files

Cloudlet's GraphQL API allows you to retrieve references to pre-existing files and associate temporary files with the object graph. The actual upload/download of files requires interaction with services external to the GraphQL schema, offered by Cloudlet as REST resources.

A persisted binary file in Livebase depends on the class on which the file attribute is declared, the name of the attribute, and the ID of the specific object/record in the class. Essentially, attributes of type file in GraphQL return an intermediate representation of Binary Files, containing metadata and references (links) to the actual resource; the actual binary files are mapped to dedicated REST resources.

Adding new files is also a two-step process: the Cloudlet exposes a REST service for uploading the binary file, which returns a temporary reference to the file (PendingFileReference); this structure must be communicated with a GraphQL mutation to associate the temporary file (not yet bound to the graph) with a given object with a file attribute, thus making the file persistent in the system.

Working with files

Uploading and downloading of Binary Files is done externally to GraphQL, via dedicated REST endpoints of the Cloudlet.

The management of files in GraphQL is structured this way in anticipation of future Livebase support for file uploads to external services; currently, the actual Binary Files (temporary and otherwise) are persisted on the Cloudlet database in a reserved table.

Reference Model #

All examples on this page reference the Employee class in the figure, and in particular, the identity_card attribute circled in red:

Employee

The Employee class, as modeled in Tutorial, to which the identity_card attribute of type file has been added.

Recover existing files #

The steps required to retrieve an existing file are:

  1. Read the reference to the file via GraphQL;
  2. Request file download via REST.

Read File References #

You can retrieve references to files via all schema services that return the <ClassName> structure, i.e. all read services and write services of type create/update/save and preview.

On type <ClassName>, attributes of type file are mapped to the following FileInfo structure:

type FileInfo {
  fileId: ID!
  link: String!
  mimeType: String!
  name: String!
  size: Int!
  uploadedOn(format: String = "default"): Datetime!
}

The fileId field contains a unique identifier of the persisted file associated with an existing object of <ClassName>; the link field contains the URI of the REST resource that allows the binary file to be downloaded. The remaining fields contain metadata and other information, such as the date the file was uploaded.

Thus, for Employee we have the following Employee structure:

type Employee {
  _id: ID!
  identity_card: FileInfo
  # attributes, outgoing roles, associates ...
  # ...
}

To download the file, it is then necessary to get the link by invoking any service that returns Employee, for example, using the get service:

{
  Employee___get(_id: "10101") {
    _id
    identity_card {
      fileId
      link
      mimeType
      name
      size
      uploadedOn
    }
  }
}
{
"data": {
"Employee___get": {
"_id": "10101",
"identity_card" {
"fileId": "101865",
"link": "https://hs4.fhoster.com/JohnDoe/Workforce/auth/file/employee/10101/identity_card",
"mimeType": "image/png",
"name": "MyCurriculum.png",
"size": 68731,
"uploadedOn": "10/10/2020 12:05:40"
}
}
}
}

Request file downloads #

Cloudlet offers the following REST endpoints for downloading binary files, under the auth/file root:

https://<CloudletURL>/auth/file/<ClassName>/<EntityID>/<FileAttributeName>

Each endpoint allows you to download the binary file associated with the <FileAttributeName> attribute of an instance of the <ClassName> class (identified by its ID, <EntityID>).

As stated here, <CloudletURL> depends on the domain on which the Cloudlet is deployed, the username of the owner account, and the name of the Cloudlet. For example, given the Cloudlet Workforce of the account JohnDoe, and given the identity_card attribute of Employee of the object with ID 10101, the corresponding endpoint is:

https://hs4.fhoster.com/JohnDoe/Workforce/auth/file/employee/10101/identity_card

The file can be retrieved with a HTTP call of type GET, authenticated as described here. For example, with cURL:

curl --output $MY_FILE -L "$MY_ENDPOINT" \
 -H "Authorization: Basic $MY_TOKEN"

Add file #

The steps required to add a new file are:

  1. Upload file via REST and get a reference to the pending-file;
  2. Associate the pending file with the desired object via GraphQL, communicating the reference to the pending file.

Make the upload of pending file. #

Cloudlet offers the following REST endpoints for uploading binary files, under the auth/file root:

https://<CloudletURL>/auth/file/<ClassName>/<FileAttributeName>

Each endpoint allows you to load a binary file which will subsequently be associated with the <FileAttributeName> attribute of an instance of the <ClassName> class.

As stated here, <CloudletURL> depends on the domain on which the Cloudlet is deployed, the username of the owner account, and the name of the Cloudlet. For example, given the Cloudlet Workforce of the account JohnDoe, and given the identity_card attribute of Employee, the corresponding endpoint is:

https://hs4.fhoster.com/JohnDoe/Workforce/auth/file/employee/identity_card

The file can be loaded with an HTTP call of type POST, authenticated as described here and containing multipart data, with key file. For example, with cURL, it is sufficient to include the -F flag and use the @ syntax to reference a local file:

curl -i "$MY_ENDPOINT" \
 -H "Authorization: Basic $MY_TOKEN" \
 -F "file=@$INPUT_FILE"

In response, the server will return a JSON object containing the reference to the newly loaded file, which is in the pending state:

{
  "pendingFileId": "d5b6106abe7c34f1d6560f4a922ba9313f3a6b20519251",
  "fileId": "519251",
  "name": "MyCurriculum.png",
  "mimeType": "image/png",
  "size": 68731,
  "uploadedOn": "10/10/2020 12:05:40"
}

Lifecycle of pending files #

The pending files are persisted on the Cloudlet database; they remain in this state for one hour, after which they are removed. It is up to the developer to associate the pending file with an object, either via GraphQL or via Plugin.
During this time, the pending files are available for download. The Cloudlet exposes the following REST endpoints for downloading pending files:

https://<CloudletURL>/auth/file/<ClassName>/<FileAttributeName>/pending/<pendingFileId>.

where <pendingFileId> is the ID returned in the JSON shown above by the upload service. Once the file is bound to an object, the download service for that pendingFileId is no longer available.

Bind pending file #

The JSON returned by the REST service for uploading is encoded in GraphQL in the input type PendingFileReference:

input PendingFileReference {
  pendingFileId: String!
  fileId: ID!
  mimeType: String!
  name: String!
  size: Int!
  uploadedOn: Datetime!
}

This input is mapped to all attributes of type file present in the input type requested by the writing services that create or modify information (create, update or save).

Taking the input <ClassName>Create as an example, for Employee we have the following EmployeeCreate structure:

input EmployeeCreate {
  identity_card: PendingFileReference

  # attributes, outgoing roles ...
  # ...
}

All input fields are required !. To associate the pending file, simply include the JSON returned by the REST service for uploading in a mutation. For this purpose, it may be convenient to use a variable to bulk-replace the PendingFileReference input:

query($file_reference: PendingFileReference!) {
  Employee___update(
    data: {
      _id: "10101",
      identity_card: $file_reference
    }
  ) {
    _id
    full_name
    identity_card {
      fileId
      link
      mimeType
      name
      size
      uploadedOn
    }
  }
}
{
  "file_reference": {
    "pendingFileId": "d5b6106abe7c34f1d6560f4a922ba9313f3a6b20519251",
    "fileId": "519251",
    "name": "MyCurriculum.png",
    "mimeType": "image/png",
    "size": 68731,
    "uploadedOn": "10/10/2020 12:05:40"
  }
}

Summary #

The REST service for uploading files is:

POST https://<CloudletURL>/auth/file/<ClassName>/<FileAttributeName>

The REST service for downloading pending files is:

GET https://<CloudletURL>/auth/file/<ClassName>/<FileAttributeName>/pending/<pendingFileId>

The REST service for downloading persistent files to the Cloudlet database is:

GET https://<CloudletURL>/auth/file/<ClassName>/<EntityID>/<FileAttributeName>