Read/Write Files (Non-RDF Resources)#
Solid Pods can store regular files (e.g., PDFs, photos, etc.) in addition to storing structured data as Things and SolidDatasets (see Read/Write Structured Data to store structured data).
The solid-client
library provides various file
handling functions. Like other data
stored in a Solid Pod, each File [1] is a Resource with a distinct
URL, which may or may not include the file extension, (e.g., .jpg
extension for an image file).
Required Access#
Note
Inrupt also supports access requests and grants. For details, see Access Requests and Grants.
The same access control mechanism
applies to these files as applies to any other Resource in the
Pod. As such, to perform file operations on restricted Resources (i.e.,
not open to the general public), the user must first authenticate as
someone with the appropriate access. Then, to make authenticated
requests, pass to the various read/write functions the authenticated
Session’s fetch
function. For more information on authentication,
see Authentication.
Action |
Required Access |
---|---|
Read a file. |
|
To write a new file to a Container. |
Either To use saveFileInContainer(), the user
must have To use overwriteFile(), the user must have
both Tip To create access policies for yet to be created files, create
a default member policy with |
To replace an existing file in a container. |
Either To use saveFileInContainer(), the user
must have To use overwriteFile(), the user must have
both |
To delete an existing file in a Container. |
Both |
Pod URL#
For files saved in a Pod, their URL acts as the unique identifier. Their URLs are relative to the Pod’s URL. For example:
https://storage.inrupt.com/{someIdentifier}/pictures/picture.jpg
https://storage.inrupt.com/{someIdentifier}/data/inventory1.pdf
where https://storage.inrupt.com/{someIdentifier}/
is the Pod’s URL.
Inrupt’s solid-client
library provides
getPodUrlAll to get the Pod’s URL or if
the user has multiple Pods, the list of Pod URLs.
import { getPodUrlAll } from "@inrupt/solid-client";
// Returns a list of URLs
const mypods = await getPodUrlAll(webID, { fetch: fetch });
Retrieve a File#
Note
Inrupt also supports access requests and grants. For details, see Access Requests and Grants.
To read a file, you can use getFile() to fetch the file content at the specified URL. The getFile() returns a File. [1] Once fetched, you can decode appropriately.
Note
To use getFile(), the user must have Read
access for the file. For more information on user access, see
Access Policies: Universal API.
The following example uses getFile() to read the specified files. The example assumes the user has the appropriate access.
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { getFile, isRawData, getContentType, getSourceUrl, } from "@inrupt/solid-client";
// ... Various logic, including login logic, omitted for brevity.
// Read file from Pod
async function readFileFromPod(fileURL) {
try {
// File (https://docs.inrupt.com/developer-tools/api/javascript/solid-client/modules/interfaces.html#file) is a Blob (see https://developer.mozilla.org/docs/Web/API/Blob)
const file = await getFile(
fileURL, // File in Pod to Read
{ fetch: fetch } // fetch from authenticated session
);
console.log( `Fetched a ${getContentType(file)} file from ${getSourceUrl(file)}.`);
console.log(`The file is ${isRawData(file) ? "not " : ""}a dataset.`);
} catch (err) {
console.log(err);
}
}
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { writeFile } from 'fs/promises';
import { getFile, isRawData, getContentType, getSourceUrl, } from "@inrupt/solid-client";
const MY_POD_URL = "https://example.com/mypod/";
const session = new Session();
// ... Various logic, including login logic, omitted for brevity.
if (session.info.isLoggedIn) {
readFileFromPod(`${MY_POD_URL}mypics/pigeon.jpg`, session.fetch, './downloaded-pigeon.jpg');
}
// ...
// Read file from Pod and save to local file
async function readFileFromPod(fileURL, fetch, saveAsFilename) {
try {
const file = await getFile(
fileURL, // File in Pod to Read
{ fetch: fetch } // fetch from authenticated session
);
console.log(`Fetched a ${getContentType(file)} file from ${getSourceUrl(file)}.`);
console.log(`The file is ${isRawData(file) ? "not " : ""}a dataset.`);
const arrayBuffer = await file.arrayBuffer();
writeFile(saveAsFilename, new Uint8Array(arrayBuffer));
} catch (err) {
console.log(err);
}
}
The above example uses:
getContentType() to return the content type; for example,
text/plain;charset=UTF-8
orimage/svg+xml
ortext/html;charset=UTF-8
. You can use getContentType() on any Resource, not just files.isRawData() to determine if the Resource is raw data (i.e., not a SolidDataset). You can use isRawData() on any Resource, not just files.
Note
You can use getFile() to retrieve a file that
contains structured data. In this case,
getContentType() on the returned
File [1]
might return text/turtle; charset=UTF-8
if the user’s Pod server
defaults to returning structured data in that format. The
isRawData() on the
File returns
false
.
Write a File#
When writing a file to a Pod, you can:
Use overwriteFile() to specify the exact destination file URL.
Use saveFileInContainer() to specify only the URL for the parent Container.
Write a File to a Specific URL#
To specify the file’s destination URL during the save, use overwriteFile(). To use overwriteFile(), pass it the following parameters:
File URL |
The destination URL for the File. If a file already exists at that URL, the function overwrites the existing file. |
||||
Options object |
An object that includes the following options:
|
Note
To use overwriteFile(), the user must have both
Write
access to the Container andWrite
access to the target file. Since the new file does not yet exist in the Container, the Container must have includedWrite
access as its default member access. For more information on user access, see Access Policies: Universal API.When using overwriteFile() to save the file to the destination URL, the Solid server creates any intermediate Container as needed.
The following example uses overwriteFile() to save the selected local files to the specified URL. The example assumes the user has the appropriate access.
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { overwriteFile, getSourceUrl } from "@inrupt/solid-client";
// ... Various logic, including login logic, omitted for brevity.
const MY_POD_URL = "https://example.com/mypod/";
// Upload selected files to Pod
function handleFiles() {
const fileList = document.getElementById('fileinput').files;
fileList.forEach(file => {
writeFileToPod(file, `${MY_POD_URL}uploadedFiles/${file.name}`, fetch);
});
}
// Upload File to the targetFileURL.
// If the targetFileURL exists, overwrite the file.
// If the targetFileURL does not exist, create the file at the location.
async function writeFileToPod(file, targetFileURL, fetch ) {
try {
const savedFile = await overwriteFile(
targetFileURL, // URL for the file.
file, // File
{ contentType: file.type, fetch: fetch } // mimetype if known, fetch from the authenticated session
);
console.log(`File saved at ${getSourceUrl(savedFile)}`);
} catch (error) {
console.error(error);
}
}
In the example, if the uploadedFiles
Container does not exist
when saving the file, the Solid server creates it to
save the file to the specified URL.
The following example reads local files and uses overwriteFile() to save the files to the specified URL. The example assumes the user has the appropriate access.
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { readFile } from 'fs/promises';
import { overwriteFile, getSourceUrl } from "@inrupt/solid-client";
const MY_POD_URL = "https://example.com/mypod/";
const session = new Session();
// ... Various logic, including login logic, omitted for brevity.
if (session.info.isLoggedIn) {
uploadFile('./pigeon.jpg', "image/jpeg", `${MY_POD_URL}mypics/pigeon.jpg`, session.fetch);
uploadFile('./report.pdf', "application/pdf",`${MY_POD_URL}mypdfs/report.pdf`, session.fetch);
}
// ...
// Read local file and save to targetURL
async function uploadFile(filepath, mimetype, targetURL, fetch) {
try {
const data = await readFile(filepath);
writeFileToPod(data, mimetype, targetURL, fetch);
} catch (err) {
console.log(err);
}
}
// Upload data as a file to the targetFileURL.
// If the targetFileURL exists, overwrite the file.
// If the targetFileURL does not exist, create the file at the location.
async function writeFileToPod(filedata, mimetype, targetFileURL, fetch) {
try {
const savedFile = await overwriteFile(
targetFileURL, // URL for the file.
filedata, // Buffer containing file data
{ contentType: mimetype, fetch: fetch } // mimetype if known, fetch from the authenticated session
);
console.log(`File saved at ${getSourceUrl(savedFile)}`);
} catch (error) {
console.error(error);
}
}
In the example, if the mypod
and mypdfs
Containers do not
exist when saving the file, the Solid server creates them to save
the file to the specified URL.
Save a File into an Existing Container#
To specify only the URL of the parent Container during the save, i.e., to let the Solid server determine the name of your file in the Container, use saveFileInContainer(). To use saveFileInContainer(), pass it the following parameters:
Container URL |
The URL of the Container where you wish to place the file. The Container must already exist. |
||||||
Options object |
An object that includes the following options:
|
Note
To use saveFileInContainer(), the user must have
Append
and/orWrite
access to the Container. For more information on user access, see Access Policies: Universal API. See also Authentication.With saveFileInContainer(), you do not control the name, and thus the URL, of your file. The Solid server may or may not use the suggested
slug
as the file name.If the specified Container does not exist, the save operation fails.
The following example reads local files and uses saveFileInContainer() to save the files into the specified Container. The example assumes the user has the appropriate access.
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { saveFileInContainer, getSourceUrl } from "@inrupt/solid-client";
// ... Various logic, including login logic, omitted for brevity.
const MY_POD_URL = "https://example.com/mypod/";
// Upload selected files into Container
function handleFiles() {
const fileList = document.getElementById('fileinput').files;
fileList.forEach(file => {
placeFileInContainer(file, `${MY_POD_URL}uploadedFiles/`);
});
}
// Upload file into the targetContainer.
async function placeFileInContainer(file, targetContainerURL) {
try {
const savedFile = await saveFileInContainer(
targetContainerURL, // Container URL
file, // File
{ slug: file.name, contentType: file.type, fetch: fetch }
);
console.log(`File saved at ${getSourceUrl(savedFile)}`);
} catch (error) {
console.error(error);
}
}
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { readFile } from 'fs/promises';
import { saveFileInContainer, getSourceUrl } from "@inrupt/solid-client";
const MY_POD_URL = "https://example.com/mypod/";
const session = new Session();
// ... Various logic, including login logic, omitted for brevity.
if (session.info.isLoggedIn) {
readAndSaveFile('./pigeon.jpg', "image/jpeg", `${MY_POD_URL}mypics/`, "mypigeon.jpg", session.fetch);
readAndSaveFile('./report.pdf', "application/pdf", `${MY_POD_URL}mypdfs/`, "myreport.pdf", session.fetch);
}
// ...
// Read local file and upload into a Container
async function readAndSaveFile(filepath, mimetype, containerURL, slug, fetch) {
try {
const data = await readFile(filepath);
placeFileInContainer(data, mimetype, containerURL, slug, fetch);
} catch (err) {
console.log(err);
}
}
// Upload data as a file into the targetContainer.
async function placeFileInContainer(filedata, mimetype, targetContainerURL, slug, fetch) {
try {
const savedFile = await saveFileInContainer(
targetContainerURL, // Container URL
filedata, // Buffer containing file data
{ slug: slug, contentType: mimetype, fetch: fetch }
);
console.log(`File saved at ${getSourceUrl(savedFile)}`);
} catch (error) {
console.error(error);
}
}
After saving the file, the example uses getSourceUrl on the returned file to determine the saved filename.
Delete a File#
To delete a file, you can use deleteFile() to remove the file at the specified URL. To use deleteFile(), pass it the following parameters:
File URL |
The URL of the file to delete. |
||
Options object |
An object that includes the following option:
|
Note
The user must have Write
access to the File. For more
information on user access, see Access Policies: Universal API. See
also Authentication.
The following example uses deleteFile() to delete the specified file. The example assumes the user has the appropriate access.
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { deleteFile } from "@inrupt/solid-client";
// ... Various logic, including login logic, omitted for brevity.
try {
// Delete the specified file from the Pod.
await deleteFile(
"https://example.com/some/boring/file", // File to delete
{ fetch: fetch } // fetch function from authenticated session
);
console.log("Deleted:: https://example.com/some/boring/file");
} catch (err) {
console.error(err);
}
// ... import statement for authentication, which includes the fetch function, is omitted for brevity.
import { deleteFile } from "@inrupt/solid-client";
const session = new Session();
// ... Various logic, including login logic, omitted for brevity.
if (session.info.isLoggedIn) {
deleteFileFromPod("https://example.com/mypod/mypics/pigeon.jpg", session.fetch);
}
// ...
async function deleteFileFromPod(fileURL, fetch) {
try {
await deleteFile(
fileURL, // File to delete from Pod
{ fetch: fetch } // fetch from the authenticated session
);
console.log(`File deleted at ${fileURL}`);
} catch (error) {
console.error(error);
}
}