All libraries and documentation are currently in Beta. Content and features are subject to change.

Read/Write Data

This page provides information on reading and writing structured data stored in Solid Pods. For information on reading and writing files (e.g., .jpg or .json) stored in Solid Pods, see Read/Write Files.

When accessing data with solid-client,

  • A Thing refers to a data entity; e.g., a person. Each Thing’s URL acts as its identifier.

    The use of the Thing’s URL facilitates interoperability. That is, to combine data, you can use a Thing’s URL to link to other data.

  • A SolidDataset is a set of Things. Each SolidDataset’s URL acts as its identifier.

    Typically, all Things in a SolidDataset have URLs relative to the SolidDataset’s URL.

From a Thing, you can access specific properties (i.e., data) about the Thing. For example, if a Thing represents a person’s contact information, specific properties for a person may include the person’s name, email addresses, etc. Each property’s URL acts as its identifier.

Vocabulary

To encourage interoperability, existing Vocabularies define reusable terms describing common data (e.g., name, title, address, url). For example, http://xmlns.com/foaf/0.1/name is part of the Friend of a Friend (FOAF) Vocabulary.

Inrupt’s vocab-common-rdf library bundles constants that refer to terms in popular pre-existing vocabularies. Applications can use these constants to read and write data. For more information on Vocabulary usage, see Use Vocabularies.

Prerequisite

By default, solid-client only enables access to public data on Solid Pods. To access other data, you must authenticate as a user who has been granted appropriate access to that data. For example, to write to a resource, the user must have Write Access on the Resource.

To authenticate, you can use the Inrupt solid-client-authn library. After authentication, the Session object obtained from solid-client-authn provides a fetch function. You can pass this function as an option to solid-client to include the user’s credentials with a request.

import {
  Session,
  getClientAuthenticationWithDependencies
} from '@inrupt/solid-client-authn-browser'
import { getSolidDataset } from "@inrupt/solid-client";
import PURL from "url-parse";

async function loginAndFetch() {
  // 1. Build a session

  const session = new Session({
    clientAuthentication: getClientAuthenticationWithDependencies({})},
    "mySession"
  );

  // 2. Start the Login Process if not already logged in.
  if (
  !session.info.isLoggedIn && 
  // Check that the authorization isn't being given before redirecting
  // to the login page.
  !new URL(window.location.href).searchParams.get("code")
  ) {
  // Redirect the user to their identity provider:
  // (This moves the user away from the current page.)
    await session.login({
      // Specify the URL of the user's OIDC issuer.
      oidcIssuer: PURL('https://inrupt.net'),
      // Specify the URL the system should redirect to after login.
      redirectUrl: PURL('https://example.com/redirect'),
  });
  }

  // 3. Complete the Login Process at your redirect site (e.g., https://example.com/redirect).
  if (!session.info.isLoggedIn) {
    // Collect information in the URL where the Identity Provider redirected
    // the user, and update session.info accordingly.
    await session.handleIncomingRedirect(window.location.href);
  }

  // 4. Make authenticated requests by passing `session.fetch` to solid-client functions. For example:
  const myDataset = await getSolidDataset(session.info.webId, { fetch: session.fetch });
  // ...
}

loginAndFetch();

For more examples, see the solid-client-authn repository.

Read Data

import {
  getSolidDataset,
  getThing,
  getStringNoLocale,
} from "@inrupt/solid-client";
import { FOAF } from "@inrupt/vocab-common-rdf";

/* 
   1. Fetch the Dataset located at the specified URL. 
*/

const profileResource = await getSolidDataset(
  "https://docs-example.inrupt.net/profile/card"
);

/*
   2. Get the data entity, specified by the URL, from the Dataset.
*/

const profile = getThing(
  profileResource,
  "https://docs-example.inrupt.net/profile/card#me"
);

// 3. Retrieve the specific data item (e.g., name) from the entity.

const name = getStringNoLocale(profileResource, FOAF.name);

To read data with solid-client,

  1. You first use getSolidDataset to fetch the dataset from which you want to read your data.

  2. Then, use either:

    • getThing to get a single data entity from the dataset, or

    • getThingAll to get all data entities from the dataset.

  3. Then, from the data entity, you can get specific data. For a list of the get functions, see apisolidclient.

1. Fetch the Dataset

To access data, first fetch the dataset (SolidDataset) that contains the data. To fetch a SolidDataset, pass its URL to getSolidDataset as in the following example:

import { getSolidDataset } from "@inrupt/solid-client";

// Fetch the Dataset located at the specified URL.

const myDataset = await getSolidDataset(
  "https://example.com/some/interesting/resource"
);

2. Get the Data Entity Thing

From the fetched dataset, you can use either:

  • getThing with the Thing’s URL to get a single data entity, or

  • getThingAll to get all data entities from the dataset.

The following passes in a example entity’s URL to getThing to retrieve the entity from the previously fetched dataset.

import { getThing } from "@inrupt/solid-client";

//  From a fetched dataset, retrieve the Thing at the specified URL.

const thing = getThing(
  myDataset,
  "https://example.com/some/interesting/resource#thing"
);

3. Read Data Attribute of a Thing

A property (i.e. data) about a Thing is identified by a URL. A property can have zero, one or more values, and the value is typed; e.g., a string, an integer, or an URL if pointing to other Things.

To encourage interoperability, certain agreed-upon Vocabularies exist to identify common data. For example, http://xmlns.com/foaf/0.1/name is part of the Friend of a Friend (FOAF) Vocabulary. http://xmlns.com/foaf/0.1/name is explicitly understood to be separate from family name or a given name. Additionally, it is understood that the name is a string, and that data entities can have more than one name.

To access data, you use the appropriate function depending on the data type, the number of values, and pass it the URL that identifies which of the Thing’s property you want.

import {
  getStringNoLocaleAll,
  getStringNoLocale,
  getUrlAll,
} from "@inrupt/solid-client";

import { FOAF } from "@inrupt/vocab-common-rdf";

// Get data from a retrieved Thing.
// - Specifically, get the name (FOAF.name).
// - Name is of type string.
// - Use getStringNoLocale if expecting a single value.
// - Use getStringNoLocaleAll if expecting multiple values.

const names = getStringNoLocaleAll(thing, FOAF.name);
// => an array of strings representing FOAF.name ("http://xmlns.com/foaf/0.1/name").

// Get data from a retrieved Thing.
// - Specifically, get the Skype ID (FOAF.skypeId).
// - Skype ID is of type string.
// - Use getStringNoLocale if expecting a single value.
// - Use getStringNoLocaleAll if expecting multiple values.

const skypeId = getStringNoLocale(thing, FOAF.skypeId);
// => one of the strings representing the FOAF.skypeId ("http://xmlns.com/foaf/0.1/skypeId"),
//    or null if there are none.

// Get data from a retrieved Thing.
// - Specifically, get the acquaintances (FOAF.knows).
// - Acquaintances is of type URL.
// - Use getStringNoLocale expecting a single value.
// - Use getStringNoLocaleAll if expecting multiple values.

const acquaintances = getUrlAll(thing, FOAF.knows);
// => an array of URLs, pointing to the Things representing FOAF.knows ("http://xmlns.com/foaf/0.1/knows")

For a list of the get functions, see thing/get.

Write Data

Write Access

To write data to a Pod requires that the user have appropriate access. For more information on access management, see Manage Access to Data (ACL).

import {
  setStringNoLocale,
  setThing,
  saveSolidDatasetAt,
} from "@inrupt/solid-client";
import { FOAF } from "@inrupt/vocab-common-rdf";

/*
   Start with a previously fetched Thing (i.e. profile).

   Use setStringNoLocale to create a NEW Thing
     (i.e., updatedProfile) with the updated name data.

   The passed-in Thing (i.e. profile) is unmodified.
*/

const updatedProfile = setStringNoLocale(profile, FOAF.name, "Vincent");

/*
   Create a new dataset (i.e., updatedProfileResource) from 
     a previously fetched dataset (i.e., profileResource) and 
     the updated profile data.
   If the profile data already exists in the existing dataset,
     the new profile data replaces the existing profile data
     in the newly created dataset.
   The passed-in dataset (i.e. profileResource) is unmodified.
*/
const updatedProfileResource = setThing(profileResource, updatedProfile);

// Save the new dataset.
const savedProfileResource = await saveSolidDatasetAt(
  "https://vincentt.inrupt.net/profile/card",
  updatedProfileResource
);

To write data with solid-client,

  1. Create a new data entity with the data you wish to write.

    To start, you need a data entity (a Thing) entity from which to create the updated Thing:

    • Use getThing to start with an existing data entity, or

    • Use createThing to create a new data entity.

    With this Thing as a starting point, use the following functions to create a new Thing with the modifications:

  2. Use setThing to return a new dataset with the updated Thing.

  3. Use saveSolidDataSetAt to save the dataset to the Pod.

Immutability

solid-client does not modify the objects provided to its functions. Instead, it creates a new object based on the provided object.

As such, the various add/set/remove functions do not modify the passed-in object. Instead, these functions return a new object with the requested changes, and the passed-in object remains unchanged.

1. Create Thing with Updated Data

To start, you need a data entity (a Thing) entity from which to create the updated Thing:

  • Use getThing to start with an existing data entity, or

  • Use createThing to create a new data entity.

The following example uses createThing.

import { createThing } from "@inrupt/solid-client";

const thing = createThing();

With this Thing as a starting point, use the following functions to create a new Thing with the modifications:

For example, the following example creates a new Thing updatedThing that has an added nickname value of "timbl". To identify the nickname, the example uses the common Vocabulary url http://xmlns.com/foaf/0.1/nick.

import { addStringNoLocale } from "@inrupt/solid-client";

let updatedThing = addStringNoLocale(
  thing,
  `http://xmlns.com/foaf/0.1/nick`,
  "timbl"
);

Only the updatedThing includes the added nickname value "timbl". The original thing remains unchanged.

Immutability

solid-client does not modify the objects provided to its functions. Instead, it creates a new object based on the provided object.

As such, the various add/set/remove functions do not modify the passed-in object. Instead, these functions return a new object with the requested changes, and the passed-in object remain unchanged.

2. Insert the Thing into a SolidDataset

After creating a new Thing with updated data, update a SolidDataset with the new Thing.

If the updated Thing was based on an existing Thing obtained from that SolidDataset, the updated Thing replaces the existing one.

import { setThing } from "@inrupt/solid-client";

const updatedDataset = setThing(myDataset, updatedThing);

3. Save the SolidDataset to a Pod

Note

To write to a Pod, you must have the required access to write the data. For more information regarding access control, see Manage Access to Data (ACL).

To save the updated dataset to a Pod, use saveSolidDatasetAt, passing in its URL as well as the updated dataset.

import { saveSolidDatasetAt } from "@inrupt/solid-client";

const savedSolidDataset = await saveSolidDatasetAt(
  "https://example.com/some/interesting/resource",
  updatedDataset

If the given URL already contains a dataset, that dataset is replaced with the updated dataset.