SpruceKit
SpruceID
  • 🌲SpruceKit Introduction
    • Decentralized Identity Overview
    • Glossary
  • ⚡Quickstart
  • SpruceKit Mobile
    • SpruceKit Showcase App
      • Installation
      • Getting Started
      • Issue a Showcase Credential
      • Present a Showcase Credential
    • SpruceKit Mobile SDK
      • Introduction
      • Core Components
        • StorageManager
        • KeyManager
        • CredentialPack
        • Card
        • IsoMdlPresentation
        • mDocReader/IsomDLReader
        • Document Scanner
      • SpruceKit iOS SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
      • SpruceKit Android SDK
        • Installation
        • Build a Wallet
          • Accept a W3C VC
          • Present a W3C VC
          • Present an mDL in-person/offline
          • Present an mDL over the internet
        • Build a Verifier
          • Verify a W3C VC
          • Verify an mDL in-person/offline
          • Verify an mDL over the internet
  • Verifiable Digital Credentials
    • ⚙️DIDKit
      • Installation
      • Core Concepts
      • DID Methods
      • Runtime Configuration
      • Specifications and Dependencies
      • Quickstart
      • DIDKit Packages
        • Command Line Interface
        • HTTP Server
        • Rust Crate
        • C Interface
        • Java and Android
        • Python
        • Javascript
      • DIDKit Examples
        • Core Functions (CLI)
        • Core Functions (HTTP)
        • did-web in minutes
        • Batch Generation & Verification
    • 🪪ISO mDL
      • Quickstart
      • Core Concepts
      • User Guide
  • Schema Definition Language
    • 🔗TreeLDR
      • TreeLDR Quickstart
        • First Schema
        • Compilation into JSON Schema
        • Compilation into JSON-LD Context
        • Writing a Layout
        • Simple Rust Integration
      • Types
        • Literal Types
      • Layouts
        • Primitive Layouts
        • Literal Layouts
        • Enumeration
        • Array Layout
        • References
      • Compiling
        • Schema Definition Formats
          • JSON Schema
          • JSON-LD Context
          • Resource Description Framework (RDF)
        • Programming Languages
          • Compiling to Rust
      • RDF Vocabulary
      • 💡TreeLDR Basics
        • Types and Layouts
        • Properties
        • Syntax
  • Witness for Credential Claims
    • 🔭Rebase
      • Core Library
      • Rust Client/Witness SDK
      • WASM Client SDK
      • Simple "Basic Post" Schema
      • DNS Witness Flow Schema
  • References
    • Contributing
    • Code of Conduct
Powered by GitBook
On this page
  • Project Creation
  • TreeLDR Schema Definitions
  • Import the Schema in Rust
  • Rebase's SchemaType Trait Implementation

Was this helpful?

  1. Witness for Credential Claims
  2. Rebase

Simple "Basic Post" Schema

PreviousWASM Client SDKNextDNS Witness Flow Schema

Last updated 10 months ago

Was this helpful?

This example shows how to create a Rust application with rebase that uses TreeLDR to define a simple self-signed basic blog post credential schema. The program will consist of:

  • a TreeLDR layout definition for type,

  • a Rust type definition automatically derived from this layout, and

  • an implementation of Rebase's SchemaType trait for this type written with the help of TreeLDR.

Project Creation

First, create a new Rust project using cargo:

cargo new basic-post-example
cd basic-post-example

The src directory will contain the sources of our application. For now, it only contains a main.rs file with a dummy main function definition.

TreeLDR Schema Definitions

In the src directory, create a new basic_post.tldr file containing the following BasicPost layout definition for https://schema.org/BlogPosting:

base <https://example.com/>;
use <http://www.w3.org/2000/01/rdf-schema#> as rdfs;
use <https://schema.org/> as schema;
use <https://treeldr.org/> as tldr;

/// Basic Blog Post.
layout BasicPost for schema:BlogPosting {
	/// Identifier of the post.
	//
	// We use the `tldr:self` property that reflects each value.
	// By using the `&rdfs:Resource`, a reference to a resource,
	// we ensure that `id` will hold a reference to itself.
	// In other word, `id` will be the identifier of the post itself.
	tldr:self as id: required &rdfs:Resource,

	/// Title of the post.
	schema:title: schema:Text,

	/// Content of the post.
	schema:body: schema:Text
}
curl https://raw.githubusercontent.com/spruceid/treeldr/main/examples/schema.org.tldr > src/schema.org.tldr

Import the Schema in Rust

treeldr-rust-macros = { git = "https://github.com/spruceid/treeldr.git" }
treeldr-rust-prelude = { git = "https://github.com/spruceid/treeldr.git" }

Then add the following module definition annotated with the #[tldr] procedural macro attribute to the src/main.rs file:

#[tldr(
	"src/schema.org.tldr",
	"src/basic_post.tldr"
)]
mod schema {
	#[prefix("https://schema.org/")]
	pub mod org {}

	#[prefix("https://example.com/")]
	pub mod example {}
}

The arguments to the #[tldr] macro lists all the files we want to include in the Rust program in the schema module. The submodules annotated with the #[prefix] macro specify where to put the types. Here every layout prefixed by https://schema.org/ will be put inside the schema::org module, while the layouts prefixed by https://example.com/ will be put inside the schema::example module.

At compile time, this macro call will expand to the following module:

mod schema {
	pub mod org {
		pub type Text = ::std::alloc::String;
	}

	pub mod example {
		pub struct BasicPost {
			id: Id,
			title: Option<super::org::Text>,
			body: Option<super::org::Text>
		}
	}
}

The schema::example::BasicPost type corresponds to our blog post schema layout.

Rebase's SchemaType Trait Implementation

We now need to implement rebase's SchemaType for BasicPost. In the src/main.rs file, add the following implementation:

use ssi::{one_or_many::OneOrMany, vc::Evidence};
use rebase::schema::schema_type::{SchemaError, SchemaType};

impl SchemaType for schema::example::BasicPost {
	fn context(&self) -> Result<serde_json::Value, SchemaError> {
		todo!()
	}

	fn types(&self) -> Result<Vec<String>, SchemaError> {
		Ok(vec![
			"VerifiableCredential".to_string(),
			"VerifiableBasicPost".to_string()
		])
	}

	fn subject(&self) -> Result<serde_json::Value, SchemaError> {
		Ok(self.into())
	}
​
	fn evidence(&self) -> Result<Option<OneOrMany<Evidence>>, SchemaError> {
		Ok(None)
	}
}

The implementation is almost complete. The only missing piece is the context method implementation that should return the JSON-LD context of the final verifiable credential (VC). This VC is a VerifiableBasicPost as stated in the types method, whose subject is the blog post itself as stated in the subject method. We can generate this JSON-LD context using TreeLDR by first defining what the final VC type will be. Create a new src/vc.tldr file with the following content:

base <https://example.com/>;
use <https://schema.org/> as schema;
use <https://www.w3.org/2018/credentials#> as vc;

type VerifiableBasicPost =
	vc:VerifiableCredential &
	all vc:credentialSubject: (schema:BlogPosting with BasicPost);
curl https://raw.githubusercontent.com/spruceid/treeldr/main/examples/vc.tldr > src/vc.tldr

We can now generate the JSON-LD context using tldrc and the following command:

tldrc -i src/schema.org.tldr -i src/vc.tldr -i src/basic_post.tldr json-ld-context -c https://www.w3.org/2018/credentials/v1 https://example.com/VerifiableBasicPost
[
	"https://www.w3.org/2018/credentials/v1",
	{
		"title": "https://schema.org/title",
		"body": "https://schema.org/body",
		"VerifiableBasicPost": "https://example.com/VerifiableBasicPost"
	}
]

The https://www.w3.org/2018/credentials/v1 context defines the VerifiableCredential type. The result can be used to define the context method. Replace the todo!() in the previous implementation with the following piece of code that includes the JSON-LD context generated thanks to TreeLDR.

Ok(serde_json::json!([
	"https://www.w3.org/2018/credentials/v1",
	{
		"title": "https://schema.org/title",
		"body": "https://schema.org/body",
		"VerifiableBasicPost": "https://example.com/VerifiableBasicPost"
	}
]))

Instead of defining the schema:BlogPosting type (and the schema:Text type) ourselves in this file, we will rely on . In the terminal, use the following command to download this file as src/schema.org.tldr:

We will embed the previous layout definition into the Rust program as a type definition using the #[tldr] procedural macro attribute provided by the . This crate relies on the . First, add those two crates to the dependencies of the Rust program by adding the following lines to the Cargo.toml file under the [dependencies] section:

We define the VerifiableBasicPost as a vc:VerifiableCredential where the credential subject is a schema:BlogPosting. The with keyword is used to specify that we will use the BasicPost layout to represent a schema:BlogPosting in the VC. Once again, we will use a TreeLDR to define the vc:VerifiableCredential type. Use the following command to download the file as src/vc.tldr:

🔭
schema.org's BlogPosting
an example file provided in the TreeLDR repository that contains schema.org type definitions
treeldr-rust-macros crate
treeldr-rust-prelude crate
example file