Skip to content
  • Vincent's avatar
    Accessing our first bits of data! · 5c534abd
    Vincent authored
    Now we're getting started! In this commit, we fetch our first bit
    of data: the name of the current user. To explain how that works,
    I'll need to give you a crash course on Linked Data - but don't
    worry, I'll limit myself only to what is absolutely necessary to
    understand what's going on.
    
    In traditional back-ends, data is usually stored in database
    tables. When your back-end is a Solid Pod, however, data is stored
    in _Documents_ living at a certain URL - you can think of these as
    being similar to HTML documents living at a URL.
    
    When a person logs in to our app, we receive a _WebID_. A WebID can
    be used both to identify that user -since no other user shares that
    URL-, and as a pointer to a Document with information relevant to
    that user.
    
    My WebID is `https://vincentt.inrupt.net/profile/card#me`. That
    means that there is a Document at
    `https://vincentt.inrupt.net/profile/card` that contains data
    relevant to me.
    
    The most important thing to understand when writing a Solid app is
    how that data is represented. In a nutshell, a Document contains a
    list of relationships between things. For example, the Document
    referred to by my WebID contain the following relationships:
    
    | <some person> | has name  | Vincent   |
    | <some person> | works at  | Inrupt    |
    | <some person> | job title | Developer |
    
    (The common terminology is: every row contains a _Statement_, with
    in the first column the Statement's _Subject_, in the second column
    a _Predicate_, and the _Object_ in the third column.)
    
    You might notice that the table above is a description of
    `<some person>`: it's someone whose name is Vincent, who works at
    Inrupt and is a developer. However, `<some person>` is not really
    usable as a stable and unique identifier: for all we know, someone
    else might have a Document elsewhere that uses the exact same
    identifier. To solve this problem, Solid uses URLs as unique
    identifiers: after all, the Document that describes the entries
    already has a URL, and we can be sure that no other Document uses
    the same one.
    
    And like specific elements in an HTML document can be referred to
    by appending their ID to the document's URL, we can give elements
    we want to describe in a Document a unique identifier. As you might
    have been able to guess, instead of `<some person>` we can use
    `me` - hence the WebID
     `https://vincentt.inrupt.net/profile/card#me`!
    
    So now we might consider my Document to look as follows:
    
    | #me | has name  | Vincent   |
    | #me | works at  | Inrupt    |
    | #me | job title | Developer |
    
    But there's one more thing to consider: interoperability. An
    important tenet of Solid is being able to give multiple apps access
    to the same data: if I enter my name at service A, I don't want to
    have to re-enter it at service B. But if one service uses "name" to
    refer to a person's full name, whereas the other uses it to refer
    to a person's last name only, that would nip interoperbility in
    the bud.
    
    What's needed here is unique terms that have an agreed-upon
    definition. And just like we can have a Document describing me, we
    could also make Documents describing a term. And in fact, many
    people have done exactly that, for many different terms you might
    want to use. These Documents are called _Vocabularies_, and there's
    one for things you might want to put on a business card at
    http://www.w3.org/2006/vcard/ns — the _vCard_ Vocabulary. It
    contains Statements along the lines of:
    
    (As a shorthand for `http://www.w3.org/2006/vcard/ns#role`, we
    will use `vcard:role`.)
    
    So now we can use `vcard:role`, and be relatively confident that
    every other app using it will use it in the way described at that
    URL. We can combine terms from different Vocabularies, e.g. the
    FOAF ("Friend of a friend") vocabulary has a term to refer to a
    person's name at `http://xmlns.com/foaf/0.1/name`. My Document
    could thus look something like this:
    
    | #me | foaf:name               | Vincent   |
    | #me | vcard:organization-name | Inrupt    |
    | #me | vcard:role              | Developer |
    
    Everything that needs to be uniquely defined has a URL, with some
    _Literal_ values for the rest ("Vincent", "Inrupt", "Developer").
    You could imagine "Inrupt" to be replaced by a URL as well,
    pointing to a Document describing the organisation itself - but for
    the intents and purposes of this tutorial, we will leave it at this.
    (It might give you some insight into why all this is referred to as
    "Linked Data" though!)
    
    A Document can describe multiple things. As an example, my Document
    could also have an entry for my address, and then link that to me:
    
    | #me       | foaf:name               | Vincent             |
    | #me       | vcard:organization-name | Inrupt              |
    | #me       | vcard:role              | Developer           |
    | #me       | vcard:hasAddress        | #address1           |
    | #address1 | vcard:street-address    | 155 Country Lane    |
    | #address1 | vcard:region            | Cottingshire County |
    
    Phew! That should cover about all the Linked Data theory you should
    know to start working with Solid. So now let's see what's actually
    happening in this commit.
    
    The only user-visible change in this commit is that their name will
    be shown when they are logged in, and a foaf:name is present in
    their profile Document. So how is this done?
    
    The magic is in the newly added `fetchProfile` function. This
    function does two things:
    
    First, it requests the user's WebID from `solid-auth-client`. When
    the user has logged in using the authentication mechanism we added
    in an earlier commit, this will return their WebID, i.e. the URL to
    a Document container a representation of the user.
    
    Then, with the WebID in hand, it uses a library called _Tripledoc_
    to retrieve that document's content. Then, `document.getSubject`
    returns a representation of all the Statements in that document
    that have the user's WebID as the Subject - so in the example table
    above, the rows with `#me` in the first column rather than
    `#address1`.
    
    `useProfile` is then called in the `<Dashboard>` component.
    Although `useProfile` provides access to all Statements about the
    user in their profile, we're currently only really interested in
    their name. We're going to use the `name` predicate of FOAF for
    this, so we're looking for a Statement like:
    
    | #me | http://xmlns.com/foaf/0.1/name | Vincent |
    
    Since `useProfile` returned all Statements with `#me` as the
    Subject, the Dashboard has access to it through `profile`. We can
    access the name by calling:
    
        const name = profile.getString('http://xmlns.com/foaf/0.1/name');
    
    That returns a the user's name, if set to a literal string value,
    rather than a URL that points to a different Document.
    
    There are a number of Vocabularies that define terms used in many
    types of apps. To save you from having to copy-paste the URL of a
    Vocabulary time and time again, the `rdf-namespaces` package
    includes some useful helper objects for common Vocabularies —
    such as FOAF. Thus, the above can be shortened to:
    
        import { foaf } from 'rdf-namespaces';
        const name = profile.getString(foaf.name);
    
    Finally, one disadvantage of Solid, as a developer, is that there
    are no guarantees about the data you want to access: you cannot be
    sure that a piece of data exists. The user might not have provided
    their name, or used a different Vocabulary to represent it. Thus,
    we should take into account that `profile.getString` might return
    `null`.
    5c534abd