Migrating to Phase 4 API: Service Layer Removal

This guide helps you migrate from the service layer API (dids, credentials, wallets) to the new direct methods API introduced in Phase 4.

Overview

Phase 4 simplifies the TrustWeave API by removing the service layer indirection. Common operations are now available as direct methods on TrustWeave, making the API more intuitive and discoverable.

Snippet convention: Blocks labeled Before still show the legacy service API (e.g. trustweave.credentials.verify and a boolean-style verification.valid). Prefer the After patterns: sealed VerificationResult (is VerificationResult.Valid / exhaustive when) and allErrors for messages—not the old valid flag.

What Changed

Removed from Public API:

  • trustweave.dids property
  • trustweave.credentials property
  • trustweave.wallets property

New Direct Methods:

  • trustWeave.createDid() — DID creation (DidCreationResult)
  • trustWeave.resolveDid() — DID resolution (DidResolutionResult)
  • trustWeave.issue { } — Credential issuance (IssuanceResult)
  • trustWeave.verify() / trustWeave.verify { } — Credential verification (VerificationResult)
  • trustWeave.wallet { } — Wallet creation (WalletCreationResult)

Still Available (complex services):

  • trustWeave.blockchains — Anchoring via BlockchainService
  • trustWeave.contractsSmartContractService

Migration Steps

Step 1: Update DID Operations

Before (Service Layer)

1
2
3
4
5
6
7
val trustweave = TrustWeave.quickStart()

// Create DID
val did = trustweave.dids.create()

// Resolve DID
val result = trustweave.dids.resolve("did:key:...")

After (Direct Methods)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val trustweave = TrustWeave.quickStart()

// Create DID - Direct method
val did = trustweave.createDid()

// Resolve DID - Direct method with sealed result
when (val result = trustweave.resolveDid("did:key:...")) {
    is DidResolutionResult.Success -> {
        println("Resolved: ${result.document.id}")
    }
    is DidResolutionResult.Failure.NotFound -> {
        println("DID not found: ${result.did}")
    }
    is DidResolutionResult.Failure.MethodNotRegistered -> {
        println("Method not registered: ${result.method}")
    }
    // ... handle other cases
}

Step 2: Update Credential Operations

Before (Service Layer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Issue credential
val credential = trustweave.credentials.issue(
    issuer = issuerDid.id,
    subject = buildJsonObject {
        put("id", holderDid.id)
        put("name", "Alice")
    },
    config = IssuanceConfig(
        proofType = ProofType.Ed25519Signature2020,
        keyId = issuerKeyId,
        issuerDid = issuerDid.id
    ),
    types = listOf("UniversityDegreeCredential")
)

// Verify credential
val verification = trustweave.credentials.verify(credential)
if (verification.valid) {
    println("Valid!")
}

After (Direct Methods)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.trustweave.credential.results.getOrThrow

// Issue credential — DSL returning IssuanceResult
val credential = trustWeave.issue {
    credential {
        type("UniversityDegreeCredential")
        issuer(issuerDid)
        subject {
            id(holderDid)
            "name" to "Alice"
        }
    }
    signedBy(issuerDid = issuerDid, keyId = issuerKeyId)
}.getOrThrow()

// Verify credential — sealed VerificationResult
val verification = trustWeave.verify(credential)
when (verification) {
    is VerificationResult.Valid -> {
        println("Valid! ${verification.credential.id}")
    }
    is VerificationResult.Invalid.Expired -> {
        println("Expired at ${verification.expiredAt}")
    }
    is VerificationResult.Invalid.Revoked -> {
        println("Revoked")
    }
    // ... handle other cases
}

Step 3: Update Wallet Operations

Before (Service Layer)

1
2
3
4
5
6
7
8
9
// Create wallet
val wallet = trustweave.wallets.create(
    holderDid = holderDid.id,
    walletId = "my-wallet-id",
    type = WalletType.InMemory
)

// Store credential
wallet.store(credential)

After (Direct Methods)

1
2
3
4
5
6
7
8
9
10
import org.trustweave.trust.types.getOrThrow

// Create wallet — WalletBuilder DSL + WalletCreationResult
val wallet = trustWeave.wallet {
    id("my-wallet-id")
    holder(holderDid)
    provider("inMemory")
}.getOrThrow()

wallet.store(credential)

Complete Migration Example

Before (Service Layer API)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
val trustweave = TrustWeave.quickStart()

// DIDs
val issuerDid = trustweave.dids.create()
val holderDid = trustweave.dids.create()
val issuerKeyId = issuerDid.verificationMethod.first().id

// Credentials
val credential = trustweave.credentials.issue(
    issuer = issuerDid.id,
    subject = buildJsonObject {
        put("id", holderDid.id)
        put("name", "Alice")
    },
    config = IssuanceConfig(
        proofType = ProofType.Ed25519Signature2020,
        keyId = issuerKeyId,
        issuerDid = issuerDid.id
    ),
    types = listOf("PersonCredential")
)

val verification = trustweave.credentials.verify(credential)
if (!verification.valid) {
    throw Exception("Invalid credential")
}

// Wallets
val wallet = trustweave.wallets.create(holderDid = holderDid.id)
wallet.store(credential)

After (Direct Methods API)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import org.trustweave.credential.results.getOrThrow
import org.trustweave.trust.types.getOrThrow
import org.trustweave.trust.types.getOrThrow

val trustWeave = TrustWeave.quickStart()

// DIDs — sealed DidCreationWithKeyResult (unwrap for examples)
val (issuerDid, issuerKeyId) = trustWeave.createDidWithKey().getOrThrow()
val (holderDid, _) = trustWeave.createDidWithKey().getOrThrow()

// Credentials — issue { } + IssuanceResult
val credential = trustWeave.issue {
    credential {
        type("PersonCredential")
        issuer(issuerDid)
        subject {
            id(holderDid)
            "name" to "Alice"
        }
    }
    signedBy(issuerDid = issuerDid, keyId = issuerKeyId)
}.getOrThrow()

// Verification — VerificationResult
val verification = trustWeave.verify(credential)
when (verification) {
    is VerificationResult.Valid -> {
        // Credential is valid
    }
    is VerificationResult.Invalid -> {
        throw Exception("Invalid credential: ${verification.allErrors.joinToString()}")
    }
}

// Wallets — WalletBuilder DSL
val wallet = trustWeave.wallet {
    holder(holderDid)
    provider("inMemory")
}.getOrThrow()
wallet.store(credential)

Error Handling Changes

DID Resolution

Before

1
2
3
4
5
6
val result = trustweave.dids.resolve("did:key:...")
if (result.document != null) {
    // Success
} else {
    // Failure - check result.metadata.error
}

After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
when (val result = trustweave.resolveDid("did:key:...")) {
    is DidResolutionResult.Success -> {
        // Access result.document directly
        println("Resolved: ${result.document.id}")
    }
    is DidResolutionResult.Failure.NotFound -> {
        println("DID not found: ${result.did}")
    }
    is DidResolutionResult.Failure.MethodNotRegistered -> {
        println("Method not registered: ${result.method}")
        println("Available: ${result.availableMethods}")
    }
    // ... exhaustive handling
}

Credential Verification

Before

1
2
3
4
5
6
val verification = trustweave.credentials.verify(credential)
if (verification.valid) {
    // Success
} else {
    // Check error details (e.g. allErrors) and trust-layer helpers (e.g. proofValid) as needed.
}

After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val verification = trustWeave.verify(credential)
when (verification) {
    is VerificationResult.Valid -> {
        // Credential is valid
        println("Valid: ${verification.credential.id}")
        verification.warnings.forEach { println("Warning: $it") }
    }
    is VerificationResult.Invalid.Expired -> {
        println("Expired at ${verification.expiredAt}")
    }
    is VerificationResult.Invalid.Revoked -> {
        println("Revoked at ${verification.revokedAt}")
    }
    is VerificationResult.Invalid.InvalidProof -> {
        println("Invalid proof: ${verification.reason}")
    }
    // ... handle all cases
}

Benefits of Migration

  1. Simpler API: Direct methods are more intuitive
    1
    2
    
    // Before: trustweave.dids.create()
    // After: trustweave.createDid()
    
  2. Better Discoverability: Common operations are obvious
    1
    2
    3
    4
    
    // Obvious what these do
    trustweave.createDid()
    trustWeave.issue { ... }
    trustWeave.wallet { holder(...); provider(...) }
    
  3. Type Safety: Sealed results provide exhaustive handling
    1
    2
    3
    4
    5
    
    // Compiler ensures all cases handled
    when (val result = trustweave.resolveDid(...)) {
        is Success -> ...
        is Failure -> ... // Must handle all failure types
    }
    
  4. Clearer Error Handling: Sealed classes make error handling explicit
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    // Before: Check boolean flags
    if (!verification.valid) { ... }
       
    // After: Handle specific error types
    when (verification) {
        is Valid -> ...
        is Invalid.Expired -> ...
        is Invalid.Revoked -> ...
    }
    

Migration Checklist

  • Replace trustweave.dids.create() with trustweave.createDid()
  • Replace trustweave.dids.resolve() with trustweave.resolveDid() and update error handling
  • Replace trustweave.credentials.issue() with trustWeave.issue { } (handle IssuanceResult)
  • Replace trustweave.credentials.verify() with trustWeave.verify() and use sealed class handling
  • Replace trustweave.wallets.create() with trustWeave.wallet { … } (handle WalletCreationResult)
  • Update error handling to use sealed result types
  • Test all changes thoroughly
  • Update any custom code that accesses service layer

Complex Services (Unchanged)

Complex services remain as properties because they have many methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Blockchain operations - Still use service
val anchor = trustweave.blockchains.anchor(
    data = credentialJson,
    serializer = JsonElement.serializer(),
    chainId = chainId
)

val readData = trustweave.blockchains.read<JsonElement>(
    ref = anchor.ref,
    serializer = JsonElement.serializer()
)

// Contract operations - Still use service
val contract = trustweave.contracts.draft(request)
val bound = trustweave.contracts.bindContract(...)

Backward Compatibility

The service classes (DidService, CredentialService, WalletService) are now internal and cannot be accessed directly. If you have code that:

  1. Accesses service properties directly: Update to use direct methods
  2. Imports service classes: Remove imports (classes are internal)
  3. Extends service classes: Use composition instead

Common Issues

Issue 1: Cannot Resolve dids, credentials, or wallets

Error:

1
Unresolved reference 'dids'

Solution: Replace with direct methods:

1
2
3
4
5
// Before
val did = trustweave.dids.create()

// After
val did = trustweave.createDid()

Issue 2: Type Mismatch in Verification Result

Error:

1
Unresolved reference 'valid'

Solution: Use sealed class pattern matching:

1
2
3
4
5
6
7
8
// Before
if (verification.valid) { ... }

// After
when (verification) {
    is VerificationResult.Valid -> { ... }
    else -> { ... }
}

Issue 3: DID Resolution Returns Different Type

Error:

1
Type mismatch: expected DidResolutionResult, found ...

Solution: Update to handle sealed result:

1
2
3
4
5
6
7
8
9
10
11
// Before
val result = trustweave.dids.resolve(did)
if (result.document != null) { ... }

// After
when (val result = trustweave.resolveDid(did)) {
    is DidResolutionResult.Success -> {
        // result.document available
    }
    else -> { ... }
}

Testing Migration

  1. Run Tests: Ensure all tests pass with new API
  2. Check Error Handling: Verify sealed result handling works
  3. Validate Functionality: Test all DID, credential, and wallet operations
  4. Performance: Verify no performance regressions

Need Help?

If you encounter issues during migration:

  1. Check Error Handling Guide for error patterns
  2. Review API Reference for method signatures
  3. Open an issue on GitHub with migration details
  4. Contact support at www.geoknoesis.com

Summary

Phase 4 API simplifies TrustWeave by:

  • Removing service layer indirection
  • Adding direct methods for common operations
  • Improving type safety with sealed results
  • Enhancing discoverability

Migration is straightforward: replace service property calls with direct method calls and update error handling to use sealed result types.


This site uses Just the Docs, a documentation theme for Jekyll.