Question about retrieving data

Firstly, please forgive the stupid questions, I have limited programming experience.

I’m messing about with Solid and I’ve created a POD. I haven’t been able to do a lot with it apart from enter my name, email and add a profile photo. Anyway, i have managed to login to my website and retrieve/display my name using the “profile viewer tutorial”.

So to get the profile name i used…
const fullName = store.any($rdf.sym(person), FOAF(‘name’));

I would like to also retrieve other info but i’m not sure how to do it. i had a look at the Solid HTTPS REST API Spec, but i couldn’t make sense of any of it.

I have tried things like…
const email = store.any($rdf.sym(person), FOAF(‘email’)); console.log(email)

…but to no avail. Can someone please inform me of how to fetch other profile data such as email, profile pic, etc. using JS?

Have you seen the thread Some basic resources for newcomers? I think it’s quite useful for a lot of people coming into the Solid technologies :slight_smile:

Also https://solid.inrupt.com/docs/getting-started is a good place to start I think :slight_smile:

I think you got it right. What happens? You write “to no avail” - but what does that imply? I assume you get no errors - just an empty value since you do not have an e-mail associated with your profile.

Got to your profile card at (for instance) https://YOURNAME.solid.community/profile/card#me, fold-out your card (click the triangle), hover the mouse over your name and click on the </> icon that appears.

Now you can see the actual RDF source from your card and what values you have and their corresponding predicates (like FOAF(‘email’)).

1 Like

Thanks for the reply’s. I managed to get it to load some stuff, e.g.

const VCARD = new $rdf.Namespace('http://www.w3.org/2006/vcard/ns#');
let picture = store.any(me, VCARD('hasPhoto'));
console.log(picture.value);
let role = store.any(me, VCARD('role'));
console.log(role.value);
let note = store.any(me, VCARD('note'));
console.log(note.value);

I wasn’t able to load the email address but that was due to an issue in the pod, e.g…
Outline.expand: Unable to fetch mailto:me@me.com: Failed to load

Anyway, it’s a start :wink: Next i need to figure out how to write to the POD (maybe tomorrow)

2 Likes

Maybe you can find my little “Object to RDF mapper” at https://github.com/JornWildt/SolidRC/blob/master/wwwroot/js/ORDFMapper.js useful for some research. It allows you to define a mapping between simple JavaScript objects and linked data resources - and uses RDFLIB to access the POD.

1 Like

And this thread covers my discoverings on the subject: My first app - adding resources?

I’ve managed to use RDFLIB without any low level HTTP work. Add, Query, Delete works like this:

Adding resource at URL X:

  • Add statements <X, some-predicate, some-value, X> for each property of the resource. Use store.add(X,p,v,X) to save the statements locally;
  • PUT the new statements onto the web: Use fetcher.putBack(X);

Reading list of resources:

  • Load all resources into local store using “globbing”. Use fetcher.load('baseUrl/*")
  • Extract all the found data from the local store. Use store.match(…)

Remove a single resource at url X:

  • Remove the resource from the web. Use fetcher.delete(X).
  • Remove local knowledge of the resource: Use store.removeDocument(X).
  • Remove all local statements: Use store.removeMatches(X);
2 Likes

Oh, and beware that the web-oriented operations in the fetcher are all async using promises.

It took me awhile to figure out why my “refresh list” operation did not include a newly added resource. That was because the “put” operation executed asynchronously and did not complete before the refresh list called the server for a an update.

Be careful to add await .then() and .catch() to the right places in your code.

3 Likes

I posted this some time ago. I didn’t get very far and so i gave up and moved on. However, I want to try again.

In my ttl file I have the entry
n:hasEmail "me@myemail.com";

I can retrieve this email address using…

let email = store.any($rdf.sym(webIdFromUrl), VCARD('hasEmail'));
console.log(email.value); // me@myemail.com

This works with my ttl file, but not with others. The email stored in other ttl files look something like this…
n:hasEmail :id1586990017267;
Or…
:id1586990017267 n:value <mailto:someone@something.com>.

Of course, when i try to access this data, I get the id, and not the address. So how do i access the email address? I’ve also tried various other things such as…

const email = store.any($rdf.sym(webIdFromUrl), FOAF('mbox'));
and…
const email = store.any($rdf.sym(webIdFromUrl), FOAF('email'));

But nothing is returning the email address.

To be clear, i’m not really interested in linked data. I’m sure it’s really cool, and perhaps i’ll look into it more at a later date, but right now i’m much more interested in the concept of a personal datastore. So I don’t want to spend days learning about RDF in order to do something that should be very simple.

P.S. This post tends to come up on most related Google search terms. So instead of posting a link to the documentation, which people can find anyway through a quick search, it would make more sense for the Solid team to provide some clear examples here, that way other people can use it as a reference :wink:

1 Like

I had another go with ldflex. Again, the last time tried to use ldflex I wasn’t able to get it to work. The good news (if you want to call it that) is that i have finally manage to read ONE persons email address. And this is because the email is stored as foaf:mbox <Ruben’s email>. So basically, there seems to be a problem reading the Vcard.

Below are some statements that i’ve tried, and the results.

solid.data['https://devolution.inrupt.net/profile/card#me'].name
returns my name
solid.data['https://devolution.inrupt.net/profile/card#me'].email
returns undefined
solid.data['https://rubenverborgh.inrupt.net/profile/card#me'].email
returns undefined
solid.data['https://ruben.verborgh.org/profile/#me'].email
returns mailto:<ruben’s email address>
solid.data['https://ruben.verborgh.org/profile/#me'].name
returns <ruben’s name>
solid.data['https://ruben.verborgh.org/profile/#me'].role
returns undefined

I tried multiple statements with multiple different webId’s. I’m able to retrieve most peoples names, but that’s about it. So does ldflex only work with foaf?

EDIT: I’m coming to the conclusion that it’s not possible. I assume that the reason why both the vcard email and address are encrypted is to prevent applications from scraping peoples personal data. Would that be a correct assumption? If that’s the case, i’m not sure why I was able to get it through foaf.

Hi @glensimister ,
Welcome back to your exploration…
First, “undefined” is not an error in that case, it’s often because the data is not there :wink:

Don’t be affraid with RDF & linked Data, it 's all about things and links between those things…

i’m using ldflex largely for my projects as you can see
agora/config-get-view.js at dd67463799c22ce1dbfa01495807659796f94f13 · scenaristeur/agora · GitHub .
but i think email is a little particular as it can have many values and can not be directly accessed on a POD.
First , ldflex does not only have foaf, here are all the vocabs I’ve found in the @solid/context of the package.json
context/context.json at master · solid/context · GitHub

I’ve never used email, but i just created emails on a test POD to try
TO get email you can test that POD https://spoggy-test.solid.community/profile/card#me

When you put email through the databrowser (see the “</>” icon to look at the data ) , the data is stored like that

...
:id1587748083850 a n:Home; n:value <mailto:test@solid.test>.

:id1587748108886 a n:Dom; n:value <mailto:swing@pop.boo>.

:id1587748123046 n:value <mailto:hello@me.cool>.

:id1587748147974 a n:Dom; n:value <tel:0123456789>.

:id1587748173361 a n:Home; n:value <tel:9876543210>.

:id1587748195447
    n:country-name "My Contry";
    n:locality "The town";
    n:postal-code "12345";
    n:region "Cool region";
    n:street-address "00 my street".
:id1587748237533
    n:country-name "Somewhere";
    n:locality "UnderTheSea";
    n:postal-code "888888";
    n:region "Sea Under";
    n:street-address "123 another street".
:me
    a schem:Person, n0:Person;
    n:fn "Spoggy-Test";
    n:hasAddress :id1587748195447, :id1587748237533;
    n:hasEmail :id1587748083850, :id1587748108886, :id1587748123046;
    n:hasPhoto <highres_274291645%5B1%5D.jpeg>;
    n:hasTelephone :id1587748147974, :id1587748173361;
    n:note "what is the note";
    n:organization-name "Smag0";
    n:role "Tester";
...

Well now, How to retrieve that ?
The example on ldflex-query repo are pointing to @RubenVerborgh server and seems to be a little bit outdated or not really compatible with the Pod implementation.

For example to retrieve the name on a POD
solid.data['https://devolution.inrupt.net/profile/card#me'].name
that is a shortcut of foaf:name does not work on a pod as it search as you mentionned to foaf:name…

You must use solid.data['https://devolution.inrupt.net/profile/card#me'].vcard$fn

:wink:

For the data on my pod :

solid.data['https://spoggy-test.solid.community/profile/card#me'].vcard$fn --> NAME

same with vcard$role, vcard$hasPhoto …and so on… a little issue with organization-name as it is a composed predicate… :thinking:

so to get organization-name, you can replace vcard prefix by its uri, and something like

await solid.data['https://spoggy-test.solid.community/profile/card#me']["http://www.w3.org/2006/vcard/ns#organization-name"]

Well, now when you suppose there are many values (like emails), ldflex-query must be used with for await ... as indicated on Ldflex/ldflex repo GitHub - LDflex/LDflex: A JavaScript DSL for querying Linked Data on the Web

So looking at the data structure stored on the POD,
you must find the objects of triples whose predicate is vcard$hasEmail then when you got the objects of that triple, follow the predicate vcard$value.

I’ve not tried yet but something like the following must give you what you expected

 for await (const emailId of solid.data['https://spoggy-test.solid.community/profile/card#me'].vcard$hasEmail)
    console.log(`- ${emailId}`);
    let email = await solid.data[${emailId }].vcard$value
    console.log(`${email}`)
}

Be carefull of the backquotes that allow to wait for the promise to be complete :wink:
Is that ok for you ??

Last but not least, to help to build Solidarity Chat, i’ve put a layer on top of ldflex to retrieve the basic data of a pod (not email yet but could be ;-)) Here is the Shighl lib

1 Like

Hi. Thanks for taking the time to answer. I quickly tried the following code based on your suggestion…

for await (const emailId of solid.data['https://spoggy-test.solid.community/profile/card#me'].vcard$hasEmail) {
console.log(`- ${emailId}`);
let email = solid.data[`${emailId }`].vcard$value
 console.log(`${email}`)
 }

However, I still seem to be faced with the same problem. In the console I get…

https://spoggy-test.solid.community/profile/card#id1587748083850
undefined
https://spoggy-test.solid.community/profile/card#id1587748108886
undefined
https://spoggy-test.solid.community/profile/card#id1587748123046
undefined

So it’s finding the email addresses, but i’m not able to extract the value. Anyway, i’ll spend a bit more time on this tomorrow (it’s getting late now) and see if i can figure out what the problem is.

I got it! I just needed to add await!

let email = await solid.data[${emailId }].vcard$value

Thanks dude! :smile:

3 Likes

Really Nice :+1:it’s not really hard but there are some tricks to know… so the best way I think is to share experience :blush:
Edited my first answer to fix

You will certainly need to write data too, so some tricks :

2 Likes

Ldflex is great. I’ve been able to add friends. However, I couldn’t seem to find an example of how to remove them. I had a wild guess at: await me.friends.remove(friend), which threw a type error “me.friends.remove is not a function” - not surprisingly. Any ideas about this?

Also, i managed to check if someone was my friend, but i think my code is a bit long winded. This is what I’ve tried…

export async function checkFriends(me, them) {
    return new Promise(async resolve => {
        for await (const friend of me.friends) {
            // remove /profile/card#me to ensure consistency
            let isFriend = await getWebIdOrigin(friend); 
            if (them === isFriend) {
                resolve(true);
            }
        }
        resolve(false);
    });
}

Is that about right? Or is there a simpler way?

Have you tried the delete keyword? Never used ldflex myself, but it looks like it’s what you want

Thanks for the info. I did actually try to use delete(), but nothing happened, not even an error message. e.g. await me.friends.delete('https://rubenverborgh.inrupt.net/profile/card#me');

However, at least I now know the correct keyword :wink:

I’ll keep playing around…

Hi~when i try to user solid.data[‘https://spoggy-test.solid.community/profile/card#me’].vcard$fn get the name,there is an error in the console:
ERROR in ./src/index.js 47:15
Module parse failed: Unexpected token (47:15)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See Concepts | webpack
|
| async function showPerson(){

solid.data[]

| }
|

webpack 5.28.0 compiled with 1 error in 19 ms
i 「wdm」: Failed to compile.
i 「wdm」: Compiling…
× 「wdm」: asset index.js 7.69 MiB [emitted] (name: main)
cached modules 6.65 MiB [cached] 1291 modules
runtime modules 1.25 KiB 6 modules
./src/index.js 1.71 KiB [built] [code generated]

ERROR in ./src/index.js 9:0-60
Module not found: Error: Package path ./dist/constants is not exported from package D:\solid\demoapp\node_modules@inrupt\solid-client (see exports field in D:\solid\demoapp\node_modules@inrupt\solid-client\package.json)

Are there the solid need any other operations to make it userful?

Hi @wenjingli-qa, welcome to the Solid forum! Could you show the actual code you’re using, and the libraries you’re trying to use.

In lieu of that I’m going to make some assumptions here that might help you. The first is that your reference to solid.data implies that you’re using @solid/query-ldflex. I’m not an expert in LDflex, but your query (i.e. solid.data[‘https://spoggy-test.solid.community/profile/card#me’].vcard$fn) looks good, in the sense that I don’t see any errors when executing it in the LDflex playground. That said, the profile you’re looking at (spoggy-test.sol...) doesn’t load for me at this time, so I’m not getting any results, but trying it with my profile it seems to work fine.

Then there is the actual error message, which refers to @inrupt/solid-client. That seems to indicate that there’s a statement like the following somewhere in your code:

import { /* something */ } from "@inrupt/solid-client/dist/constants";

It might be that your editor inserted that, but solid-client does not allow you to import from dist/constants, hence the error message. Removing that import statement (which I’m assuming is unused) should solve that message for you.

1m

Thanks for your reply~ :grinning: i removed that import statement, run in my browser has a new error as follows:
index.js:43 Uncaught (in promise) ReferenceError: solid is not defined
at showPerson (index.js:43)
at HTMLButtonElement.buttonRead.onclick (index.js:53)
showPerson @ index.js:43
buttonRead.onclick @ index.js:53

my the actual code as follow,don’t i do something wrong?:
import { login,handleIncomingRedirect,getDefaultSession, fetch} from “@inrupt/solid-client-authn-browser”;
const { PathFactory } = require(‘ldflex’);
const { default: ComunicaEngine } = require(’@ldflex/comunica’);
const { namedNode } = require(’@rdfjs/data-model’);
const buttonLogin = document.querySelector("#btnLogin");
const buttonRead = document.querySelector("#btnRead");
// 1a. Start Login Process. Call login() function.
function loginToInruptDotCom() {return login({oidcIssuer: “https://liwenjing.solid.fuxitechnology.cn/”,
redirectUrl: window.location.href,}); }
async function handleRedirectAfterLogin() {
await handleIncomingRedirect();
const session = getDefaultSession();
if (session.info.isLoggedIn) {
// Update the page with the status.
document.getElementById(“labelStatus”).textContent = “Your session is logged in.”;
document.getElementById(“labelStatus”).setAttribute(“role”, “alert”);}}
// The example has the login redirect back to the index.html.
// This calls the function to process login information.
// If the function is called when not part of the login redirect, the function is a no-op.
handleRedirectAfterLogin();
async function showPerson(){
const name = solid.data[‘https://liwenjing.solid.fuxitechnology.cn/profile/card#me’].vcard$fn;
console.log(name);
}
buttonLogin.onclick = function() {
loginToInruptDotCom();
};
buttonRead.onclick = function() {
showPerson();
};

You’re trying to use LDflex together with @inrupt/solid-client-authn-browser, which unfortunately at the moment is not possible - @solid/query-ldflex assumes you are using solid-auth-client.

Additionally, you’re referencing solid.data, but you’re not importing the solid module from anywhere. It might be worth reading up on how modules in JavaScript work - it’s a bit too much for me to explain all that in a short forum post, sorry :slight_smile:

(And one other tip: if you use three backticks (i.e. `) on a line, then paste your code, then add three additional backticks on a new line, your code will be more readable to others. It looks as follows.)

const someCode = "example";
console.log(someCode);