Trails
Overview
Section titled “Overview”Trails provide a way to navigate through interconnected resources in a Solid Pod, automatically creating any missing resources along the path. They’re particularly useful for ensuring that a sequence of linked resources exists, creating them with sensible defaults if they don’t.
A trail consists of a series of steps that define how to move from one resource to the next, with fallback behaviour to create missing data.
Building a trail
Section titled “Building a trail”To create a trail, start with buildTrail(), define a starting point using .startFrom(url), then define the path through the user’s Pod using .via() calls:
import { buildTrail } from "benno/trail";import { profileModel, typeIndexModel } from "./trail-models";import { schema, solid } from "rdf-namespaces";
export const trail = buildTrail() .via({ model: profileModel, getTargetUrl: (profile) => profile.publicTypeIndex ?? null, fallback: (rootUrl, existingProfile) => { if (!existingProfile) { // If the profile was not found at the user's WebID altogether, // something is seriously wrong with the user's Pod. // We can't fix that, so bail out: throw new Error("Profiles should always exist"); } return { ...existingProfile, publicTypeIndex: `${rootUrl}/settings/publicTypeIndex`, }; }, }) .via({ model: typeIndexModel, findPointer: (typeIndexes) => { return ( typeIndexes.find( (typeIndex) => typeIndex.type === solid.TypeRegistration && typeIndex.forClass === schema.Movie, ) ?? null ); }, getTargetUrl: (typeIndex) => typeIndex.instance, fallback: (rootUrl) => { return { type: solid.TypeRegistration, forClass: schema.Movie, instance: `${rootUrl}/movies/`, }; }, });via takes one argument, an object with the following possible keys:
| Required | Type |
|---|---|
| Yes | A model |
The model that defines the structure of the Things you’re looking for at this step in the trail.
getTargetUrl
Section titled “getTargetUrl”| Required | Type |
|---|---|
| Yes | (thing) => string | null |
A function that extracts the URL of the next resource from a Thing that matches your model. If no target URL can be determined, it should return null.
fallback
Section titled “fallback”| Required | Type |
|---|---|
| Yes | (rootUrl, existingThing?) => newThing |
A function that creates a new Thing when the current step in the trail doesn’t exist. The rootUrl parameter is the Pod root URL, and existingThing is provided if a Thing was found but didn’t have a target URL. The returned Thing should point to a URL under the root URL (e.g. ${rootUrl}/example); Benno will create that resource if it does not yet exist.
findPointer
Section titled “findPointer”| Required | Type |
|---|---|
| No | (things) => thing | null |
An optional function for finding a specific Thing among all the Things in the target resource. If not provided, the trail will look for a Thing with the current resource’s URL.
Following a trail
Section titled “Following a trail”To get the URL at the end of a trail, call the .follow method.
.follow(options)
Section titled “.follow(options)”Executes the trail, navigating through each .via call and creating any missing resources along the way.
Parameters
Section titled “Parameters”options
Section titled “options”| Required | Type |
|---|---|
| No | { fetch?: typeof fetch } |
Optionally allows passing a custom fetch function. Primarily used to send authenticated requests.
Return value
Section titled “Return value”A Promise resolving to the URL of the final resource in the trail.
Error handling
Section titled “Error handling”Trails will throw errors in the following situations:
- No Pod root found: If the server doesn’t expose a Pod root URL through the appropriate headers.
- Invalid fallback: If a
.viacall’sfallbackfunction creates a Thing that itsgetTargetUrlcannot extract a target URL from. - Network errors: Standard fetch errors when accessing or creating resources.