Some Helper APIs to play SAFE with WebID and RDF.

RDF can be a pain.

It’s great once you’ve got it, but figuring out just how to describe your data, given the myriad of schemas and vocabs out there (yay decentralisation!). It can be a pain.

For us, this is clearly one of the largest blockers to people implementing RDF data in their applications. And we want RDF on SAFE. It makes sense to have it. To keep data portable. To keep users owning their data. We want RDF and we want to make it hard to get it wrong.

Even just for our own sanity! :stuck_out_tongue:

So as we were building out the POCs, we started creating some helper APIs to help simplify the process.

These are built atop the RDF Emualtion, we started creating APIs to abstract away the vocab-paralysis that can come with RDF, so when working with WebIds at least, it should be easy enough to get going.

A WebID Emulation

The WebId emulation makes creating a WebId profile document on SAFE, a simple function call:

const profile = {
  uri: 'safe://mywebid.gabriel',
  name: 'Gabriel Viganotti',
  nick: 'bochaco',
  website: 'safe://mywebsite.gabriel',
  image: 'safe://mywebsite.gabriel/images/myavatar',

const md = await authedApp.mutableData.newPublic(xorname, TYPE_TAG);
await md.quickSetup({});
const webId = await md.emulateAs('WebID');
await webId.create(profile);

This will create an RDF graph, populate it with your profile, which itself will have vocab descriptions of the data consistent with other SAFE WebIds. It creates a publicName and subdomain if needed, and populates those with appropriate RDF graphs too.

For now the profile is limited to name, nickname, img, website, but there’s nothing stopping us expanding this as we move forwards.

On top of that, we’ve added a few more helpers to the WebID emulation, to make update and serialise a breeze too!

Working it on the Web

In order to make working with already existing WebIds simpler, we added another new top level API to safe_app_nodejs: the (oh so imaginatively named) ‘web’ api: safe.web.

This features helpers for what could be more ‘normal’ SAFE tasks: createPublicName, getPublicNames, addWebIdToDirectory, getWebIds. (Bear in mind these will all generate RDF style versions of these containers, which are not currently compatible with older SAFE applications.)

The slightly ambiguous addWebIdToDirectory is used to provide a simple way of seeing all webids owned by an account. This is used as part of the webId.create emulation to save a reference to the webId’s URL to the public container, providing us one easy place to retrieve all webIds without having to request permissions to _publicNames, and then digging deeper into each public name to see if it is a webId or not. Saving us a couple of fetches.

The converse to this is the getWebIds,which will return a list of all webIds stored in the ‘directory’, (aka. the public container for now.)

All of these APIs are actively being used in both the Peruse POC and the WebId Manager.

More Help!?

That’s the last of the APIs we’ve added for the moment. But we’re aiming to provide as much help as we can to devs to help make adding RDF vocabs to their data, easy.

So comments, thoughts, PRs and suggestions are all suuuuuper welcome.


A few RDF n00b questions from me:
- so our app/site can see all WebIds that the user has available…Peruse was letting the user select which WebId to use, right? So to clarify, the idea is that if we’re building our own app from scratch, we’ll use the getWebIds to present similar ‘choose your webId’ functionality, and if we build a site meant for Peruse we don’t really need to worry about that, and will read the selected WebId directly from Peruse? edit3: this answered in the Medium article: “So web apps don’t actually have to worry about managing WebIds at all, they can focus on consuming the data”

  • would every app/site be expected to have the functionality to create new webIDs, or would that more likely be handled all through the WebId Manager? I guess probably too early to say / market will decide what expectations will be. How is it in the existing RDF&SOLID ecosystem?
  • When RDF data is created by our app/site, it gets tagged or otherwise linked with the WebId used to create it, right?

Edit: reading your other RDF thread now. Looks like it might have some of these answers.

Edit2: trimmed 3rd question after reading about RDFlib.js in other thread

Hey @drehb

On my phone, so apologies for brevity or typos!.

Would all apps create webids?

I’d hope not. Seems like there could be a range of apps to manage webids,but you choose your preference.

Any other app asking for perms for this ,I’d regard with suspicion. With webids existing a device shouldn’t need to bother with this. We could provide an API to open the management app if needed,eg.

Your second q: I imagine being up to the app/user. I don’t think that needs to be forced one way or the other


Another question - Looking at the patter app and the presentations that you guys have given, I can start to picture how everyone’s public data links together and can be crawled. Is it only really applicable to this publicly networked data, or do you guys envision user’s private data items also being stored in RDF graphs?

Everything, public, private, shared should ideally be RDF. This is the key point being made in my SAFE Plume demo at the DevCon.

Because then the different apps you use for private stuff can also work on each other’s non proprietary, non app specific data.

Also, you may wish to make use of semantics/crawling yourself on your private data, or on shared data, and of course to make some data that was once private public or shared.

Apps which keep proprietary formats will be less useful, and lock users in, which is what we are trying to get away from.


@happybeing’s plumetest app as demo’d at Dev Con doesn’t seem to authorise any more (in Peruse). Has the API changed again?

Yes, it’s changed a lot! The fixes would not be that hard but for now you should use SAFE Browser - unless that’s been updated too (or an old version of Peruse). It’s the same with most existing apps I should think. I think the changes came in in Peruse 0.6. As noted, I’m not sure about SAFE Browser.


Yes it works on Safe Browser, more or less. I can read your blogs (and fascinating they are too :wink:) but not write my own. No worries. I’ve been reading around RDF etc and thought I’d have a little play. Happy to wait for the next iteration though.

1 Like

I haven’t made it easy to set up your own blog but it isn’t that hard either. Easiest way is to clone the repo, edit the config-example.json and save as config.json, then upload the files to your own public name. This could be made easier, but I haven’t done so yet.

I think the only thing you need worry about in the config is where it specifies the storage is - that must be writable by you, so a public name you own - if you want to do this I’ll need to dig the setting out so let me know - I’ll be happy to help.

1 Like

Thanks. No rush if you’re busy. How do I specify storage in the config file?

Do I also I need to create a WebID on the network? I see you had safe://happybeing/card#me but it’s not live unfortunately so I can’t copy it.

Here is the config.json I used:

    "title": "SAFE Plume Blog (PoC)",
    "tagline": "Safe as Houses, Light as a feather",

    "picture": "safe-quill.png",
    "fadeText": true,
    "showSources": true,
    "cacheUnit": "days",
    "defaultPath": "posts",

    "owners": ["safe://happybeing/card#me"],
    "owner": {
      "name": "happybeing",
      "webid": "safe://happybeing/card#me",
      "picture": "mugshot-hb.jpg",
      "authenticated": false

    "safeAppConfig": {
      "id":     "com.happybeing.plume.poc",
      "name":   "SAFE Plume (PoC)",
      "vendor": "com.happybeing"
    "postsURL": "safe://plumeteststore/posts/"

You don’t need a WebID as that came after this (what I have in there is just for show). You can just use the same public name for everything, and you can if you want add the “postsURL” setting to use a different public name for storage, but if you leave that out it will still work - but using the same public name for everything.

Hmm. Nope - I still can’t write. plumage/posts definitely exists on the network and there are no errors in the console to suggest why. Here’s my config.json

    "title": "JPL Plume Blog",
    "tagline": "My first blog",

    "picture": "img/logo.svg",
    "fadeText": true,
    "showSources": true,
    "cacheUnit": "days",
    "defaultPath": "posts",

    "owners": ["safe://blog1.jpl9/card#me"],
    "owner": {
      "name": "JPL9",
      "webid": "safe://blog1.jpl9/card#me",
      "picture": "img/icon-blue.svg",
      "authenticated": false

    "safeAppConfig": {
      "id":     "",
      "name":   "JPL Plume Blog",
      "vendor": ""
  "postsURL": "safe://plumage/posts/"

Hmm, not sure what’s happening here then. If there was an access problem I’d expect that to show up in the console - you should see a lot of debug output there. Is that the case?

Assuming it is, can you walk me through what you do after visiting the blog and what happens. I’d expect that you won’t get to create/edit posts if you don’t have write access but I’m not clear where you get to atm.

OK - tried again on Linux (Debian), same results. I get some sort of error (failure getting config from the network) on logging into the network:

On loading safe://blog1.jpl9 I get these console messages, which simply recur whenever I try to do something (e.g. Login, create a blog, etc), which seems to happen for other sites too but in this case the webpage is unresponsive.

I’m using Safe Browser 0.10.2 and Web Hosting Manager 0.4.4.

1 Like

I don’t think we should try to debug this while the network is potentially broken, so best to try again once the all clear is announced (scheduled for Wednesday). I don’t know if that is the cause of the problems you are having but it might well be. Good for you for trying - I would very much like to get this working for you. I’ll also have more time after Friday so should be able to look into this with you.

BTW, I can’t tell for sure from the screenshot, but you may have the wrong debug console open as those are not app messages. There’s a console for the browser itself, and a separate one for each tab.

So to see what the app is doing you need to open the console for its tab: so once the page has loaded in the tab/window, right click anywhere on the page and choose “Inspect element”. That should work on either SAFE Beaker or Peruse I think.


Agree! - I’m off on me hols anyway (that’s why it’s started raining by the way, in case you were wondering), but I thought I’d give it one last go before driving off into the murk.

I hadn’t realised there was a separate console for each tabs - this is more instructive (but as you say, a job for another day!)


Have a good holiday and thanks for the rain :wink:

1 Like

@JPL This error is coming from the browser attempting to get the browser config from the network (probably due to the network issues ongoing atm). You can ignore it for your app tests, though.

1 Like