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.
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 engine model #
All examples on this page reference the Employee class in the figure, and in particular, the identity_card attribute circled in red:
Recover existing files #
The steps required to retrieve an existing file are:
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 download #
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:
- Upload file via REST and get a reference to the pending-file;
- Associate the pending file with the desired object via GraphQL, communicating the reference to the pending file.
Upload a 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.
Associate a 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>