From 5f43d60dbc6de284cf2243da71f4c5b46d820815 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Sat, 18 Dec 2021 09:03:46 +0100 Subject: [PATCH 1/4] Clean up solid files --- index.html | 2 +- solid/README.md | 9 ++++++--- solid/index.html | 4 ++-- solid/solid-file-client/README.md | 4 ++-- solid/solid-file-client/index.html | 8 +++++--- solid/solid-rest-api/README.md | 9 +++++++++ solid/solid-rest-api/index.html | 10 +++++----- 7 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 solid/solid-rest-api/README.md diff --git a/index.html b/index.html index e187290..d647697 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,7 @@

0data Hello World

This project came out of Zero Data Swap #4.

diff --git a/solid/README.md b/solid/README.md index d6f6f46..b7071a8 100644 --- a/solid/README.md +++ b/solid/README.md @@ -1,12 +1,13 @@ # Solid Hello World -This is a simple application illustrating how to get started with [Solid](https://solidproject.org/). +This folder contains some simple applications illustrating how to get started with [Solid](https://solidproject.org/) using different libraries. -It only has two dependencies: [an authentication library](https://github.com/inrupt/solid-client-authn-js) and [an RDF parsing library](https://github.com/rdfjs/N3.js). Everything else is plain HTML, CSS and JavaScript. All the functionality related with Solid is contained in a single file; `solid.js`. +- [solid-rest-api](./solid-rest-api): This example is the most minimal, it only uses the authentication library and a Turtle parser. All the interaction with the POD is implemented using the native `fetch` function. +- [solid-file-client](./solid-file-client): This example uses a higher-level library called [solid-file-client](https://github.com/jeff-zucker/solid-file-client). It's still a pretty minimal library, but makes some basic operations easier. ## Understanding the code -If you're not familiar with the basics of Solid, we strongly suggest that you check out [the glossary](Glossary.md). You can find more specific documentation about the code in this app within the [solid.js](./solid.js) file. +If you're not familiar with the basics of Solid, we strongly suggest that you check out [the glossary](Glossary.md). You can find more documentation about each code sample in the source files, they contain inline comments specific to each implementation. The `index.html` and `main.js` files are not documented, but they should be fairly easy to understand if you're already familiar with HTML and JavaScript. The application doesn't have any custom CSS because it uses a classless CSS framework called [Simple.css](https://simplecss.org). @@ -49,3 +50,5 @@ There are already some existing examples using more libraries: - [Solid To-Do App Tutorial](https://www.virginiabalseiro.com/blog/tutorial) ([React](https://reactjs.org/) + [solid-client](https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/read-write-data/)): A tutorial of how to build a To-Do app using [Inrupt](https://inrupt.com/)'s libraries. - [Ramen](https://github.com/noeldemartin/ramen) ([Vue](https://vuejs.org/) + [soukai-solid](https://github.com/noeldemartin/soukai-solid)): A simple application that adds a recipe for Ramen to your POD. This application can also serve as an example to use the type index. - [Hello Solid](https://wkokgit.github.io/hellosolid/) ([JQuery](https://jquery.com/) + [rdflib](https://github.com/linkeddata/rdflib.js)/[LDFlex](https://github.com/LDflex/LDflex)): A Solid Client application to explain the basics of Solid. Keep in mind that this library uses the deprecated [solid-auth-client](https://github.com/solid/solid-auth-client) for authentication, and will not work with newer Solid PODs. + +You can also check out [this list](https://timea.solidcommunity.net/HelloWorld/index.html). diff --git a/solid/index.html b/solid/index.html index b927e84..58a6c75 100644 --- a/solid/index.html +++ b/solid/index.html @@ -14,8 +14,8 @@

Solid Hello World Examples

Here you can find more examples following the same simple structure, but using some advanced libraries:

If you would like to see even more advanced examples, you can find them in the FAQs.

diff --git a/solid/solid-file-client/README.md b/solid/solid-file-client/README.md index b2d9a0f..18917fd 100644 --- a/solid/solid-file-client/README.md +++ b/solid/solid-file-client/README.md @@ -1,4 +1,4 @@ -# Solid Hello World +# Solid Hello World (solid-file-client) This is a simple application illustrating how to get started with [Solid](https://solidproject.org/) using the [solid-file-client](https://github.com/jeff-zucker/solid-file-client) library. @@ -6,4 +6,4 @@ It only has two dependencies: [an authentication library](https://github.com/inr ## Understanding the code & Usage instructions -This example follows the same structure as the other examples, so you follow the [same instructions](../). +This example follows the same structure as other examples in this repository, so you can follow these [general instructions](../). diff --git a/solid/solid-file-client/index.html b/solid/solid-file-client/index.html index be0d252..85e9c21 100644 --- a/solid/solid-file-client/index.html +++ b/solid/solid-file-client/index.html @@ -4,12 +4,12 @@ - Solid Hello World + Solid Hello World (solid-file-client) -

Solid-File-Client Hello World

+

Solid Hello World
(solid-file-client)

Loading...

@@ -19,10 +19,12 @@

Solid-File-Client Hello World

Hi there!

This page is a showcase of a simple Solid application - built using the solid-file-client library. You can look at the source code and learn how to use it in + built using the solid-file-client library. You can look at the source code and learn how to use it in the repository.

+

If you want to see other examples, you can find them here: Solid Hello World Examples.

+
diff --git a/solid/solid-rest-api/README.md b/solid/solid-rest-api/README.md new file mode 100644 index 0000000..6649b8e --- /dev/null +++ b/solid/solid-rest-api/README.md @@ -0,0 +1,9 @@ +# Solid Hello World (REST API) + +This is a simple application illustrating how to get started with [Solid](https://solidproject.org/). + +It only has two dependencies: [an authentication library](https://github.com/inrupt/solid-client-authn-js) and [an RDF parsing library](https://github.com/rdfjs/N3.js). Everything else is plain HTML, CSS and JavaScript. All the functionality related with Solid is contained in a single file; `solid.js`. + +## Understanding the code & Usage instructions + +This example follows the same structure as other examples in this repository, so you can follow these [general instructions](../). diff --git a/solid/solid-rest-api/index.html b/solid/solid-rest-api/index.html index a906573..55acadd 100644 --- a/solid/solid-rest-api/index.html +++ b/solid/solid-rest-api/index.html @@ -4,12 +4,12 @@ - Solid Hello World + Solid Hello World (REST API) -

Solid-Rest-Api Hello World

+

Solid Hello World
(REST API)

Loading...

@@ -19,11 +19,11 @@

Solid-Rest-Api Hello World

Hi there!

This page is a showcase of a simple Solid application - built using JavaScript, CSS and HTML. You can look at the source code and learn how to use it in the - solid-rest-api repository. + built using JavaScript, CSS and HTML. You can look at the source code and learn how to use it in + the repository.

-

If you want to see other examples, you can find them here: Solid Hello World Examples.

+

If you want to see other examples, you can find them here: Solid Hello World Examples.

From 687b1ea1a97a6169298eb34853cc42df65fe01f8 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Sat, 18 Dec 2021 10:05:35 +0100 Subject: [PATCH 2/4] Clean up solid-file-client Co-authored-by: bourgeoa --- solid/solid-file-client/solid.js | 60 ++++++++++++++++++-------------- solid/solid-rest-api/solid.js | 15 +++++--- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/solid/solid-file-client/solid.js b/solid/solid-file-client/solid.js index fa988bb..8a02856 100644 --- a/solid/solid-file-client/solid.js +++ b/solid/solid-file-client/solid.js @@ -4,6 +4,8 @@ let user, tasksContainerUrl; const solidFileClient = new SolidFileClient(solidClientAuthentication); +solidFileClient.rdf.setPrefix('schemaorg', 'https://schema.org/'); + async function restoreSession() { // This function uses Inrupt's authentication library to restore a previous session. If you were // already logged into the application last time that you used it, this will trigger a redirect that @@ -76,11 +78,8 @@ async function performTaskCreation(description) { // - SAI, or Solid App Interoperability. This one is still being defined: // https://solid.github.io/data-interoperability-panel/specification/ - if (!tasksContainerUrl) { - await createSolidContainer(`${user.storageUrl}tasks/`); - - tasksContainerUrl = `${user.storageUrl}tasks/`; - } + if (!tasksContainerUrl) + tasksContainerUrl = await createSolidContainer(`${user.storageUrl}tasks/`); const documentUrl = await createSolidDocument(tasksContainerUrl, ` @prefix schema: . @@ -122,17 +121,17 @@ async function loadTasks() { // In a real application, you shouldn't hard-code the path to the container like we're doing here. // Read more about this in the comments on the performTaskCreation function. - const tasks = []; - const containmentQuads = await readSolidDocument(`${user.storageUrl}tasks/`, null, { ldp: 'contains' }) + const containerUrl = `${user.storageUrl}tasks/`; + const containmentQuads = await readSolidDocument(containerUrl, null, { ldp: 'contains' }); - if (!containmentQuads) { + if (!containmentQuads) return []; - } - tasksContainerUrl = `${user.storageUrl}tasks/`; + tasksContainerUrl = containerUrl; + const tasks = []; for (const containmentQuad of containmentQuads) { - const [typeQuad] = await readSolidDocument(containmentQuad.object.value, null, { rdf: 'type' }, ''); + const [typeQuad] = await readSolidDocument(containmentQuad.object.value, null, { rdf: 'type' }, { schemaorg: 'Action' }); if (!typeQuad) { // Not a Task, we can ignore this document. @@ -141,8 +140,8 @@ async function loadTasks() { } const taskUrl = typeQuad.subject.value; - const [descriptionQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, ''); - const [statusQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, ''); + const [descriptionQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, { schemaorg: 'description' }); + const [statusQuad] = await readSolidDocument(containmentQuad.object.value, `<${taskUrl}>`, { schemaorg: 'actionStatus' }); tasks.push({ url: taskUrl, @@ -156,7 +155,8 @@ async function loadTasks() { async function readSolidDocument(url, source, predicate, object, graph) { try { - // rdf.query return an array of statements matching terms (load and cache url content) + // solidFileClient.rdf.query returns an array of statements with matching terms. + // (load and cache url content) return await solidFileClient.rdf.query(url, source, predicate, object, graph); } catch (error) { return null; @@ -192,10 +192,12 @@ async function deleteSolidDocument(url) { } async function createSolidContainer(url) { - const response = await solidFileClient.createFolder(url) + const response = await solidFileClient.createFolder(url); if (!isSuccessfulStatusCode(response.status)) throw new Error(`Failed creating container at ${url}, returned status ${response.status}`); + + return url; } function isSuccessfulStatusCode(statusCode) { @@ -211,30 +213,36 @@ function getSolidDocumentUrl(resourceUrl) { } async function fetchUserProfile(webId) { - const [nameQuad] = await readSolidDocument(webId, null, { foaf: 'name' }) + const [nameQuad] = await readSolidDocument(webId, null, { foaf: 'name' }); + const [storageQuad] = await readSolidDocument(webId, null, { space: 'storage' }); + return { url: webId, name: nameQuad?.object.value || 'Anonymous', - storageUrl: await findeUserStorage(webId), + + // WebIds may declare more than one storage url, so in a real application you should + // ask which one to use if that happens. In this app, in order to keep it simple, we'll + // just use the first one. If none is declared in the profile, we'll search for it. + storageUrl: storageQuad?.object.value || await findUserStorage(webId), }; } -async function findeUserStorage(url) { +// See https://solidproject.org/TR/protocol#storage. +async function findUserStorage(url) { url = url.replace(/#.*$/, ''); url = url.endsWith('/') ? url + '../' : url + '/../'; url = new URL(url); - // following solid/protocol used by NSS and CSS - const response = await solidFileClient.head(url.href) + const response = await solidFileClient.head(url.href); - if (response.headers.get('Link')?.includes('; rel="type"')) { - return url.href - } + if (response.headers.get('Link')?.includes('; rel="type"')) + return url.href; - // for providers that don't advertise storage properly - if (url.pathname === '/') return url.href + // Fallback for providers that don't advertise storage properly. + if (url.pathname === '/') + return url.href; - return findeUserStorage(url.href); + return findUserStorage(url.href); } function escapeText(text) { diff --git a/solid/solid-rest-api/solid.js b/solid/solid-rest-api/solid.js index e69602b..2199099 100644 --- a/solid/solid-rest-api/solid.js +++ b/solid/solid-rest-api/solid.js @@ -75,11 +75,8 @@ async function performTaskCreation(description) { // - SAI, or Solid App Interoperability. This one is still being defined: // https://solid.github.io/data-interoperability-panel/specification/ - if (!tasksContainerUrl) { - await createSolidContainer(user.storageUrl, 'tasks'); - - tasksContainerUrl = `${user.storageUrl}tasks/`; - } + if (!tasksContainerUrl) + tasksContainerUrl = await createSolidContainer(user.storageUrl, 'tasks'); const documentUrl = await createSolidDocument(tasksContainerUrl, ` @prefix schema: . @@ -228,6 +225,10 @@ async function createSolidContainer(url, name) { if (!isSuccessfulStatusCode(response.status)) throw new Error(`Failed creating container at ${url}, returned status ${response.status}`); + + const location = response.headers.get('Location'); + + return new URL(location, url).href; } function isSuccessfulStatusCode(statusCode) { @@ -250,6 +251,10 @@ async function fetchUserProfile(webId) { return { url: webId, name: nameQuad?.object.value || 'Anonymous', + + // WebIds may declare more than one storage url, so in a real application you should + // ask which one to use if that happens. In this app, in order to keep it simple, we'll + // just use the first one. If none is declared in the profile, we'll search for it. storageUrl: storageQuad?.object.value || await findUserStorage(webId), }; } From 8762b8174c2101e0ae7506737a7cfb0fdb841900 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Sat, 18 Dec 2021 10:11:11 +0100 Subject: [PATCH 3/4] Update n3 CDN --- solid/solid-rest-api/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solid/solid-rest-api/index.html b/solid/solid-rest-api/index.html index 55acadd..80c0964 100644 --- a/solid/solid-rest-api/index.html +++ b/solid/solid-rest-api/index.html @@ -37,7 +37,7 @@

Your tasks

- + From 46e913f9bd813002f3b38d2edebcd793bf2c49e1 Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Sun, 19 Dec 2021 08:18:19 +0100 Subject: [PATCH 4/4] Make solid-file-client default Solid example --- index.html | 2 +- solid/README.md | 2 +- solid/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index d647697..faf2271 100644 --- a/index.html +++ b/index.html @@ -20,7 +20,7 @@

0data Hello World

This project came out of Zero Data Swap #4.

diff --git a/solid/README.md b/solid/README.md index b7071a8..8dfafb9 100644 --- a/solid/README.md +++ b/solid/README.md @@ -2,8 +2,8 @@ This folder contains some simple applications illustrating how to get started with [Solid](https://solidproject.org/) using different libraries. +- [solid-file-client](./solid-file-client): This example uses a higher-level library called [solid-file-client](https://github.com/jeff-zucker/solid-file-client). It's pretty minimal library, but makes some basic operations easier. - [solid-rest-api](./solid-rest-api): This example is the most minimal, it only uses the authentication library and a Turtle parser. All the interaction with the POD is implemented using the native `fetch` function. -- [solid-file-client](./solid-file-client): This example uses a higher-level library called [solid-file-client](https://github.com/jeff-zucker/solid-file-client). It's still a pretty minimal library, but makes some basic operations easier. ## Understanding the code diff --git a/solid/index.html b/solid/index.html index 58a6c75..2c7b621 100644 --- a/solid/index.html +++ b/solid/index.html @@ -14,8 +14,8 @@

Solid Hello World Examples

Here you can find more examples following the same simple structure, but using some advanced libraries:

If you would like to see even more advanced examples, you can find them in the FAQs.