Skip to main content

Quickly prototype schemas

This guide provides a hands-on walk-through of the end-to-end workflow for rapid prototyping with static schemas using the SDK. This approach allows you to define, publish, version, and test schemas to iterate on your solution quickly.

Step 1: Define a schema with a UDT

First, define a schema using user-defined types (UDTs) in your code. Use the @VcSchema decorator to define a unique identifier (slug) and a version number of the schema.

// Define a UDT for a "basic profile" credential schema
@VcSchema(slug = "basic-profile", version = 1)
class BasicProfileClaims {
@NotEmpty
String firstName;

String lastName;
}

Step 2: Publish the schema

Next, publish the schema using the VcDecorator from your UDT. The publishSchema() method sends the schema to the Truvity platform, making it immutable and publicly accessible for verification.

important

Once a schema is published, its definition is permanently frozen and cannot be changed. This is a core principle of Verifiable Credentials. To make changes, you must publish a new version of the schema.

// Create a decorator from your UDT
VcDecorator<BasicProfileClaims> basicProfileDecorator = client.vcDecorator(BasicProfileClaims.class);

// Publish the schema
SchemaPublicationResult result = basicProfileDecorator.publishSchema();
if (result.published) {
System.out.println("Schema published successfully");
} else {
System.out.println("Failed to publish schema: " + result.error);
}

Step 3: Test interoperability

The published schema can now be used to issue a verifiable credential. Any party can then verify the credential against the public definition of the schema, proving its interoperability.

You can also retrieve the public URL of the schema for discoverability and sharing.

// Create a draft using the published schema
DraftCredentialWithClaims<BasicProfileClaims> createdDraft =
basicProfileDecorator.create(new BasicProfileClaims() {
{
claims.firstname = "John";
claims.lastName = "Doe";
}
});

// Generate a private key for signing if it doesn't exist
ResourceKeyPublic privateKey = client.keys()
.keyGenerate(KeyGenerateRequest.builder()
.data(KeyGenerate.builder().type(KeyGenerateType.P_256).build())
.build());

// Issue a credential from the draft
VerifiableCredentialWithClaims<BasicProfileClaims> issuedCredential = createdDraft.issue(privateKey.getId());

// Verify the credential
VerificationResult verificationResult = issuedCredential.verify();

if (verificationResult.verified()) {
System.out.println("Credential verified successfully!");
} else {
System.out.println("Credential verification failed.");
}

Step 4: Create and publish a new schema version

As part of the credential schema lifecycle, you most likely need to make updates to a published schema to align with new business or regulatory requirements.

To make a change to the schema, you must create a new version. Define a new UDT with an incremented version number and your changes, and then publish it.

// Define an updated UDT for the "basic profile" credential schema to version 2
@VcSchema(slug = "basic-profile", version = 2)
class BasicProfileClaimsV2 {
@NotEmpty
String firstName;

String lastName;

// Add a new field
LocalDate birthDate;
}

// Create a decorator from the new UDT
VcDecorator<BasicProfileClaimsV2> basicProfileDecoratorV2 = client.vcDecorator(BasicProfileClaimsV2.class);

// Publish the new version
SchemaPublicationResult result = basicProfileDecoratorV2.publishSchema();
if (result.published) {
System.out.println("Schema v2 published successfully");
} else {
System.out.println("Failed to publish schema: " + result.error);
}
Tip

If you want to only add new fields when extending an existing schema definition, you don't need to copy and paste the full UDT definition and can use class extension instead. The following example shows how to do that.

// Define an updated UDT for the "basic profile" credential schema to version 2
@VcSchema(slug = "basic-profile", version = 2)
class BasicProfileClaimsV2 extends BasicProfileClaims {
// Add a new field
LocalDate birthDate;
}

Step 5: Test interoperability of a new schema version

Finally, test the interoperability of the new schema version by creating and verifying a credential.

// Create a draft using the latest published schema (v2)
DraftCredentialWithClaims<BasicProfileClaimsV2> createdDraftV2 =
basicProfileDecoratorV2.create(new BasicProfileClaimsV2() {
{
firstName = "John";
lastName = "Doe";
birthDate = LocalDate.of(1990, 1, 1);
}
});

// Assume 'privateKey' is the private key generated in a previous step
VerifiableCredentialWithClaims<BasicProfileClaimsV2> issuedCredentialV2 =
createdDraftV2.issue(privateKey.getId());

// Verify the credential
VerificationResult verificationResultV2 = issuedCredentialV2.verify();

if (verificationResultV2.verified()) {
System.out.println("Credential v2 verified successfully!");
} else {
System.out.println("Credential v2 verification failed.");
}

Further reading