TrustWeave uses a type-safe system for identifiers and domain types to prevent errors, improve code clarity, and make APIs more intuitive. This guide explains how to work with identifiers and types in TrustWeave.
Quick Start
1
2
3
4
5
6
7
8
9
10
11
12
importorg.trustweave.did.identifiers.Didimportorg.trustweave.credential.identifiers.CredentialIdimportorg.trustweave.credential.types.ProofTypeimportorg.trustweave.credential.types.CredentialType// ✅ Identifiers - identify WHICH resourcevaldid=Did("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")valcredId=CredentialId("https://example.com/credentials/123")// ✅ Types - classify WHAT KIND of resourcevalproofType=ProofType.Ed25519Signature2020valcredType=CredentialType.Education
Understanding the Distinction
Identifiers: “Which Resource?”
Identifiers are unique references to specific resources. They answer the question: “Which one?”
Format: URIs/IRIs following RFC 3987 (e.g., did:key:..., https://...)
Purpose: Point to a specific entity, credential, or document
Validation: Format is validated at creation time
Serialization: Serialize as strings in JSON
1
2
3
4
// ✅ Identifiers point to specific resourcesvalissuerDid=Did("did:key:z6Mk...")// Which DID?valcredentialId=CredentialId("https://...")// Which credential?valissuerId=IssuerId("did:web:example.com")// Which issuer?
Types: “What Kind?”
Types are classifications that categorize concepts. They answer the question: “What kind?”
Format: Enums or sealed classes with predefined values
Purpose: Classify and categorize (proof algorithm, credential category, etc.)
Validation: Must be one of the allowed values
Serialization: Serialize as strings (category names)
1
2
3
4
// ✅ Types classify resourcesvalproofType=ProofType.Ed25519Signature2020// What kind of proof?valcredType=CredentialType.Education// What kind of credential?valpurpose=StatusPurpose.REVOCATION// What purpose?
Quick Reference Table
Aspect
Identifiers
Types
Question
“Which resource?”
“What kind?”
Package
{module}.identifiers
{module}.types
Structure
Classes extending Iri
Sealed classes / Enums
Examples
Did, CredentialId
ProofType, CredentialType
Validation
Format (IRI/DID pattern)
Value (allowed categories)
Working with Identifiers
Creating Identifiers
All identifiers are created using constructor-like syntax. They validate automatically and throw IllegalArgumentException if invalid.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
importorg.trustweave.did.identifiers.Didimportorg.trustweave.credential.identifiers.CredentialIdimportorg.trustweave.credential.identifiers.IssuerIdimportorg.trustweave.core.identifiers.KeyId// ✅ Direct construction (validates format automatically)valdid=Did("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")valcredId=CredentialId("https://example.com/credentials/123")valissuerId=IssuerId("did:web:example.com")valkeyId=KeyId("key-1")// ❌ Invalid formats throw IllegalArgumentExceptiontry{valinvalidDid=Did("not-a-did")// Throws!}catch(e:IllegalArgumentException){println("Invalid DID format: ${e.message}")}
Safe Parsing
Use extension functions for safe parsing when the input might be invalid:
1
2
3
4
5
6
7
8
9
10
11
importorg.trustweave.did.identifiers.toDidOrNullimportorg.trustweave.credential.identifiers.toCredentialIdOrNull// ✅ Safe parsing (returns null if invalid)valdid=json.getString("issuer")?.toDidOrNull()valcredId=userInput.toCredentialIdOrNull()// Use with Kotlin null-safetydid?.let{issuerDid->// Use issuerDid safely}
Working with DIDs
DIDs have specialized methods and operators for common operations:
importorg.trustweave.did.identifiers.Didimportorg.trustweave.did.identifiers.VerificationMethodIdimportorg.trustweave.core.identifiers.KeyIdvaldid=Did("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")// Extract DID methodvalmethod=did.method// "key"// Extract identifiervalidentifier=did.identifier// "z6Mk..."// Create verification method IDvalvmId1=did+"key-1"// Operator syntaxvalvmId2=didwith"key-1"// Infix syntax (more readable)valvmId3=didwithKeyId("key-1")// Type-safe with KeyId// Check DID methodif(didisMethod"key"){println("This is a did:key DID")}// Get base DID (without path/fragment)valbaseDid=did.baseDid
Creating Verification Method IDs
Verification Method IDs combine a DID with a key fragment:
importorg.trustweave.did.identifiers.VerificationMethodIdimportorg.trustweave.core.identifiers.KeyIdvaldid=Did("did:key:z6Mk...")// ✅ Three ways to create VerificationMethodId// 1. Using operator (concise)valvmId1=did+"key-1"// Creates "did:key:z6Mk...#key-1"// 2. Using infix (more readable)valvmId2=didwith"key-1"// 3. Using constructor (most explicit)valvmId3=VerificationMethodId(did=did,keyId=KeyId("key-1"))// ✅ Parsing from stringvalvmId4=VerificationMethodId.parse("did:key:z6Mk...#key-1")// ✅ Decomposeval(didPart,keyIdPart)=vmId4.decompose()// ✅ Extract key ID fragment using type-safe extension functionimportorg.trustweave.did.identifiers.extractKeyIdvalvmId=VerificationMethodId(did,KeyId("#key-1"))valkeyId=vmId.extractKeyId()// Returns "key-1" (without # prefix)// Or directly from VerificationMethodvalverificationMethod=document.verificationMethod.firstOrNull()valkeyId2=verificationMethod?.extractKeyId()// Returns "key-1" or null
Type Inheritance: All Identifiers are IRIs
All identifiers extend the base Iri class, enabling polymorphism:
importorg.trustweave.core.identifiers.Iriimportorg.trustweave.did.identifiers.Didimportorg.trustweave.credential.identifiers.CredentialIdvaldid=Did("did:key:z6Mk...")valcredId=CredentialId("https://example.com/cred/123")// ✅ All identifiers can be used as Irivaliri1:Iri=did// Did IS-A Irivaliri2:Iri=credId// CredentialId IS-A Iri// ✅ Use Iri features on any identifierfunprocessIri(iri:Iri){when{iri.isHttpUrl->println("HTTP/HTTPS URL: ${iri.value}")iri.isDid->println("DID: ${iri.value}")iri.isUrn->println("URN: ${iri.value}")}}processIri(did)// Prints: "DID: did:key:..."processIri(credId)// Prints: "URI: https://..."
Converting Between Identifier Types
1
2
3
4
5
6
7
8
9
10
11
12
13
14
importorg.trustweave.did.identifiers.Didimportorg.trustweave.credential.identifiers.CredentialIdimportorg.trustweave.credential.identifiers.IssuerIdvaldid=Did("did:key:z6Mk...")// ✅ Convert DID to other identifier typesvalissuerId=IssuerId.fromDid(did)valcredId=CredentialId.fromDid(did)// If credential ID is a DID// ✅ Narrow Iri to specific typevaliri:Iri=didvalasDid=iri.asDidOrNull()// Returns Did if valid, null otherwisevalasCredId=iri.asCredentialIdOrNull()
Working with Types
Proof Types
Proof types specify the cryptographic signature algorithm:
importorg.trustweave.credential.types.CredentialTypeimportorg.trustweave.credential.types.CredentialTypes// ✅ Standard typesvalverifiableCred=CredentialType.VerifiableCredential// Always requiredvaleducation=CredentialType.Educationvalemployment=CredentialType.Employmentvalcertification=CredentialType.Certification// ✅ Using convenience constantsvaltypes1=listOf(CredentialTypes.VERIFIABLE_CREDENTIAL,// Always requiredCredentialTypes.EDUCATION)// ✅ Custom credential typevalcustomType=CredentialType.Custom("ProfessionalLicenseCredential")// ✅ From stringvalfromString=CredentialType.fromString("EducationCredential")// ✅ In VerifiableCredentialvalcredential=VerifiableCredential(type=listOf(CredentialType.VerifiableCredential,CredentialType.Education),// ...)
Status Purpose
Status purpose indicates why a status list exists:
1
2
3
4
5
6
7
8
9
10
11
12
13
importorg.trustweave.credential.types.StatusPurpose// ✅ Enum valuesvalrevocation=StatusPurpose.REVOCATION// For revoking credentialsvalsuspension=StatusPurpose.SUSPENSION// For suspending credentials// ✅ In CredentialStatusvalstatus=CredentialStatus(id=StatusListId("https://..."),type="StatusList2021Entry",statusPurpose=StatusPurpose.REVOCATION// Typed!// ...)
Schema Format
Schema format specifies the validation schema type:
1
2
3
4
5
6
7
8
9
10
11
12
importorg.trustweave.credential.types.SchemaFormat// ✅ Enum valuesvaljsonSchema=SchemaFormat.JSON_SCHEMA// JSON Schema Draft 7/2020-12valshacl=SchemaFormat.SHACL// SHACL for RDF// ✅ In CredentialSchemavalschema=CredentialSchema(id=SchemaId("https://..."),type="JsonSchemaValidator2018",schemaFormat=SchemaFormat.JSON_SCHEMA// Typed!)
Using in Models
Verifiable Credential
All identifier and type fields are now strongly typed:
// ✅ Compiler prevents these mistakes:funverifyCredential(credId:CredentialId,issuer:IssuerId){// ...}valdid=Did("did:key:z6Mk...")valcredId=CredentialId("https://...")verifyCredential(did,credId)// ❌ Compile error: Did != CredentialId// ✅ Correct usageverifyCredential(credId,IssuerId.fromDid(did))
IDE Autocomplete
IDEs provide better autocomplete and navigation:
1
2
3
4
5
6
7
8
// ✅ IDE knows available proof typesvalproofType=ProofType.// IDE suggests: Ed25519Signature2020, JsonWebSignature2020, etc.// ✅ IDE knows available credential typesvalcredType=CredentialType.// IDE suggests: Education, Employment, etc.// ✅ IDE knows DID methodsvalmethod=did.method// IDE knows this returns String, suggests methods
Refactoring Safety
Type-safe identifiers make refactoring safer:
1
2
3
// ✅ Renaming or moving identifiers is caught at compile time// ✅ Find all usages works accurately// ✅ Safe to extract to functions with typed parameters
importorg.trustweave.did.identifiers.toDidOrNullimportorg.trustweave.credential.identifiers.toCredentialIdOrNullimportkotlinx.serialization.json.Jsonimportkotlinx.serialization.json.jsonObjectimportkotlinx.serialization.json.jsonPrimitivefunparseCredentialFromJson(jsonString:String):VerifiableCredential?{returntry{valjson=Json.parseToJsonElement(jsonString).jsonObject// ✅ Safe parsing with extension functionsvalid=json["id"]?.jsonPrimitive?.content?.toCredentialIdOrNull()valissuer=json["issuer"]?.jsonPrimitive?.content?.toDidOrNull()?.let{IssuerId.fromDid(it)}?:returnnull// ... parse rest of credentialVerifiableCredential(id=id,issuer=issuer,// ...)}catch(e:Exception){null}}
Pattern: Working with Collections
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importorg.trustweave.did.identifiers.Didimportorg.trustweave.credential.identifiers.CredentialId// ✅ Type-safe collectionsvaldids:List<Did>=listOf(Did("did:key:z6Mk..."),Did("did:web:example.com"))valcredIds:Set<CredentialId>=setOf(CredentialId("https://example.com/cred/1"),CredentialId("https://example.com/cred/2"))// ✅ Filter by typevalkeyDids=dids.filter{itisMethod"key"}// ✅ Map to strings when neededvaldidStrings=dids.map{it.value}
Pattern: Type Narrowing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
importorg.trustweave.core.identifiers.Iriimportorg.trustweave.did.identifiers.Didimportorg.trustweave.did.identifiers.asDidOrNullfunprocessIri(iri:Iri){// ✅ Narrow Iri to Did if it's a DIDvaldid=iri.asDidOrNull()if(did!=null){// Handle as DIDprintln("DID method: ${did.method}")}else{// Handle as other IRIprintln("Other IRI: ${iri.value}")}}
Best Practices
✅ DO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ✅ Use typed identifiers everywherevaldid=Did("did:key:z6Mk...")valcredId=CredentialId("https://...")// ✅ Use safe parsing for user input or JSONvaldid=userInput.toDidOrNull()?:return// ✅ Leverage type inheritancefunacceptAnyIri(iri:Iri){/* ... */}acceptAnyIri(did)// ✅ WorksacceptAnyIri(credId)// ✅ Works// ✅ Use companion factory methods when availablevalissuerId=IssuerId.fromDid(did)// More semantic than IssuerId(did.value)
❌ DON’T
1
2
3
4
5
6
7
8
9
10
11
12
13
// ❌ Don't use String for identifiersfunprocessCredential(id:String){}// Use CredentialId instead// ❌ Don't bypass validationvaldid=Did("not-a-did")// Will throw - use safe parsing instead// ❌ Don't mix identifier typesfunprocess(did:Did,credId:CredentialId){if(did.value==credId.value){}// Type mismatch - probably wrong logic}// ❌ Don't use strings for typesvalproofType:String="Ed25519Signature2020"// Use ProofType instead