Skip to content

Commit 3597380

Browse files
author
Joshua Coffey
authored
Template documentation update (#1333)
1 parent 0dd8213 commit 3597380

File tree

11 files changed

+496
-166
lines changed

11 files changed

+496
-166
lines changed

docs/reference/other/openid.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,17 @@ Some credential template fields may be intended for URLs which resolve to images
118118

119119
By default, these will display to the holders in the OIDC flow as simple text fields containing the raw URL. However, the template can be configured to display these URLs as either inline embedded images, or convenient links to download the linked data.
120120

121-
When creating a Template:
122-
123-
- Choose the `Uri` type for any Fields which are intended to contain URIs.
124-
- Set the `trinsic/web.display_method` annotation on the Field
125-
- If the field is intended to contain an image, use the value `inline`.
126-
- Otherwise, use the value `download`.
127-
- Set the `trinsic/file.content_type` annotation on the Field
128-
- Use the value `image` if the field is intended to contain a link to an image
129-
- Otherwise, the value should be the expected MIME Type of the data
130-
- If you are unsure, use `application/octet-stream` as a catch-all
121+
When creating or updating a Template:
122+
123+
- Choose the `URI` type for any Fields which are intended to contain URIs.
124+
- Configure the `UriData` object on the Field
125+
- Set the `RenderMethod` property
126+
- If the field is intended to contain an image, use the value `INLINE_IMAGE`.
127+
- Otherwise, use `LINK` for a clickable link, or `TEXT` to display the URI in raw form.
128+
- Set the `MimeType` property
129+
- Use the value `image` if the field is intended to contain a link to an image
130+
- Otherwise, the value should be the expected MIME Type of the data
131+
- If you are unsure, use `application/octet-stream` as a catch-all
131132

132133
## Sample
133134

docs/reference/services/template-service.md

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,17 @@
44
The Template Service allows you to manage and search [Credential Templates](/learn/concepts/templates).
55

66

7-
!!! info "Templates are optional"
8-
Templates are designed to be a helpful abstraction over the complexities of producing valid [JSON-LD Verifiable Credentials](https://www.w3.org/TR/vc-data-model/).
9-
10-
You aren't required to use templates; if you produce valid JSON-LD VCs yourself, they can be issued through Trinsic.
11-
127
---
138

149
## Create Template
1510

16-
!!! info "Field Annotations"
17-
When defining the Fields of a Template, the `annotations` object can be used to set arbitrary key-value metadata on a Field.
11+
Creates a new credential template.
1812

19-
Trinsic defines certain annotations that dictate how a credential field containing a URI will render during the verification flow.
13+
The `name` of a template must be unique within your ecosystem, and cannot be changed -- it is used to derive the URI of the template itself.
2014

21-
[Click here](../../reference/other/openid.md) for more information on this use case.
15+
The `title` and `description` parameters (for the template itself, as well as for any of its fields) should be human-readable strings. They should describe the credentials issued by the template, not the template itself (for example, a good title for a medical license template would simply be "Medical License", not "Medical License Template").
2216

23-
Creates a new credential template.
17+
`field_ordering` may be used to specify the order in which fields are rendered when displaying a credential, and to categorize fields into logical sections. This is used for display only, and has no bearing on working with credentials as an issuer or verifier.
2418

2519
{{ proto_sample_start() }}
2620
=== "Trinsic CLI"
@@ -31,7 +25,7 @@ Creates a new credential template.
3125
=== "TypeScript"
3226
<!--codeinclude-->
3327
```typescript
34-
[CreateTemplate](../../../web/test/CredentialTemplateShared.ts) inside_block:defineTemplate
28+
[CreateTemplate](../../../web/test/CredentialTemplates.test.ts) inside_block:createTemplate
3529
```
3630
<!--/codeinclude-->
3731

@@ -67,14 +61,67 @@ Creates a new credential template.
6761

6862
---
6963

64+
## Update Template
65+
66+
Updates a template's display metadata, such as its human-readable title/description.
67+
68+
This call cannot be used to update templates in a way that might invalidate previously-issued credentials: fields cannot be added, removed, or renamed, but their `title` and `description` properties may be updated.
69+
70+
In order to leave a property unchanged (for example, if you wish to change `description` but not `title`), simply leave it unspecified (_don't_ set it to an empty string/object). This applies to fields as well: any field not specified in `fields` will remain unchanged.
71+
72+
{{ proto_sample_start() }}
73+
=== "Trinsic CLI"
74+
```bash
75+
Not yet supported
76+
```
77+
78+
=== "TypeScript"
79+
<!--codeinclude-->
80+
```typescript
81+
[UpdateTemplate](../../../web/test/CredentialTemplates.spec.ts) inside_block:updateTemplate
82+
```
83+
<!--/codeinclude-->
84+
85+
=== "C#"
86+
<!--codeinclude-->
87+
```csharp
88+
[UpdateTemplate](../../../dotnet/Tests/Tests.cs) inside_block:updateTemplate
89+
```
90+
<!--/codeinclude-->
91+
92+
=== "Python"
93+
<!--codeinclude-->
94+
```python
95+
[UpdateTemplate](../../../python/samples/templates_demo.py) inside_block:updateTemplate
96+
```
97+
<!--/codeinclude-->
98+
99+
=== "Go"
100+
<!--codeinclude-->
101+
```golang
102+
[UpdateTemplate](../../../go/services/template_service_test.go) inside_block:updateTemplate
103+
```
104+
<!--/codeinclude-->
105+
106+
=== "Java"
107+
<!--codeinclude-->
108+
```java
109+
[UpdateTemplate](../../../java/src/test/java/trinsic/TemplatesDemo.java) inside_block:updateTemplate
110+
```
111+
<!--/codeinclude-->
112+
113+
{{ proto_method_tabs("services.verifiablecredentials.templates.v1.CredentialTemplates.Update") }}
114+
115+
---
116+
70117
## Get Template
71118

72119
Fetches a template definition by `id`.
73120

74121
{{ proto_sample_start() }}
75122

76123
=== "Trinsic CLI"
77-
```bash
124+
```
78125
trinsic template get --id <TEMPLATE_ID>
79126
```
80127
@@ -124,7 +171,7 @@ Deletes a credential template by `id`.
124171
{{ proto_sample_start() }}
125172
=== "Trinsic CLI"
126173
```bash
127-
trinsic tamplate delete --id <TEMPLATE_ID>
174+
trinsic template delete --id <TEMPLATE_ID>
128175
```
129176

130177
=== "C#"

docs/walkthroughs/vaccination.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,6 @@ Templates are simply a list of the fields that a credential can have.
271271
```
272272
<!--/codeinclude-->
273273

274-
!!! info "Templates are Optional"
275-
276-
Templates are an optional helpful abstraction which removes the need to work directly with complex data formats such as JSON-LD.
277-
278-
When a template is used to issue a credential, the result is a valid, interoperable JSON-LD Verifiable Credential.
279-
280-
Trinsic's SDKs support issuing JSON-LD credentials that you create yourself, should you choose not to use templates.
281-
282274
!!! abstract "Further Reading: Templates"
283275

284276
- Learn more about [Templates](/learn/concepts/templates){target=_blank}

dotnet/Tests/Tests.cs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -409,15 +409,33 @@ public async Task DemoTemplatesWithIssuance() {
409409

410410
// create example template
411411
// createTemplate() {
412-
CreateCredentialTemplateRequest templateRequest = new() {
412+
CreateCredentialTemplateRequest createRequest = new()
413+
{
413414
Name = "An Example Credential",
414-
AllowAdditionalFields = false
415+
Title = "Example Credential",
416+
Description = "A credential for Trinsic's SDK samples",
417+
AllowAdditionalFields = false,
418+
Fields =
419+
{
420+
{ "firstName", new() { Title = "First Name", Description = "Given name of holder" } },
421+
{ "lastName", new() { Title = "Last Name", Description = "Surname of holder", Optional = true } },
422+
{ "age", new() { Title = "Age", Description = "Age in years of holder", Type = FieldType.Number } }
423+
},
424+
FieldOrdering =
425+
{
426+
{ "firstName", new() { Order = 0, Section = "Name" } },
427+
{ "lastName", new() { Order = 1, Section = "Name" } },
428+
{ "age", new() { Order = 2, Section = "Miscellanous" } }
429+
},
430+
AppleWalletOptions = new()
431+
{
432+
PrimaryField = "firstName",
433+
SecondaryFields = { "lastName" },
434+
AuxiliaryFields = { "age" }
435+
}
415436
};
416-
templateRequest.Fields.Add("firstName", new() { Description = "Given name" });
417-
templateRequest.Fields.Add("lastName", new());
418-
templateRequest.Fields.Add("age", new() { Optional = true }); // TODO - use FieldType.NUMBER once schema validation is fixed.
419437

420-
var template = await trinsic.Template.CreateAsync(templateRequest);
438+
var template = await trinsic.Template.CreateAsync(createRequest);
421439
// }
422440

423441
template.Should().NotBeNull();
@@ -426,12 +444,40 @@ public async Task DemoTemplatesWithIssuance() {
426444
template.Data.SchemaUri.Should().NotBeNull();
427445

428446
var templateId = template.Data.Id;
447+
448+
// update template
449+
// updateTemplate() {
450+
UpdateCredentialTemplateRequest updateRequest = new() {
451+
Id = templateId,
452+
Title = "New Title",
453+
Description = "New Description",
454+
Fields = {
455+
{ "firstName", new() { Title = "New title for firstName" } },
456+
{ "lastName", new() { Description = "New description for lastName" } }
457+
},
458+
FieldOrdering =
459+
{
460+
{ "age", new() { Order = 0, Section = "Misc" } },
461+
{ "firstName", new() { Order = 1, Section = "Full Name" } },
462+
{ "lastName", new() { Order = 2, Section = "Full Name" } },
463+
},
464+
AppleWalletOptions = new()
465+
{
466+
PrimaryField = "age",
467+
SecondaryFields = { "firstName", "lastName" }
468+
}
469+
};
470+
471+
var updatedTemplate = await trinsic.Template.UpdateAsync(updateRequest);
472+
// }
473+
474+
updatedTemplate.UpdatedTemplate.Title.Should().Be(updateRequest.Title);
429475

430476
// issue credential from this template
431477
var values = JsonSerializer.Serialize(new {
432478
firstName = "Jane",
433479
lastName = "Doe",
434-
age = "42"
480+
age = 42
435481
});
436482

437483
// issueFromTemplate() {

go/services/template_service_test.go

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@ package services
33
import (
44
"context"
55
"encoding/json"
6-
"fmt"
7-
"github.com/google/uuid"
86
"github.com/stretchr/testify/assert"
97
"github.com/trinsic-id/sdk/go/proto/services/verifiablecredentials/templates/v1/template"
108
"github.com/trinsic-id/sdk/go/proto/services/verifiablecredentials/v1/credential"
11-
129
"testing"
1310
)
1411

@@ -21,10 +18,38 @@ func TestTemplatesDemo(t *testing.T) {
2118

2219
// create example template
2320
// createTemplate() {
24-
templateRequest := &template.CreateCredentialTemplateRequest{Name: fmt.Sprintf("Example Template - %s", uuid.New()), AllowAdditionalFields: false, Fields: make(map[string]*template.TemplateField)}
25-
templateRequest.Fields["firstName"] = &template.TemplateField{Description: "Given name"}
26-
templateRequest.Fields["lastName"] = &template.TemplateField{}
27-
templateRequest.Fields["age"] = &template.TemplateField{Type: template.FieldType_NUMBER, Optional: true}
21+
templateRequest := &template.CreateCredentialTemplateRequest{
22+
Name: "An Example Credential",
23+
Title: "Example Credential",
24+
Description: "A credential for Trinsic's SDK samples",
25+
AllowAdditionalFields: false,
26+
Fields: map[string]*template.TemplateField{
27+
"firstName": {
28+
Title: "First Name",
29+
Description: "Given name of holder",
30+
},
31+
"lastName": {
32+
Title: "Last Name",
33+
Description: "Surname of holder",
34+
Optional: true,
35+
},
36+
"age": {
37+
Title: "Age",
38+
Description: "Age in years of holder",
39+
Type: template.FieldType_NUMBER,
40+
},
41+
},
42+
FieldOrdering: map[string]*template.FieldOrdering{
43+
"firstName": {Order: 0, Section: "Name"},
44+
"lastName": {Order: 1, Section: "Name"},
45+
"age": {Order: 2, Section: "Miscellaneous"},
46+
},
47+
AppleWalletOptions: &template.AppleWalletOptions{
48+
PrimaryField: "firstName",
49+
SecondaryFields: []string{"lastName"},
50+
AuxiliaryFields: []string{"age"},
51+
},
52+
}
2853

2954
templateResponse, err := trinsic.Template().Create(context.Background(), templateRequest)
3055
// }
@@ -35,6 +60,40 @@ func TestTemplatesDemo(t *testing.T) {
3560
assert2.NotNil(templateResponse.Data.Id)
3661
assert2.NotNil(templateResponse.Data.SchemaUri)
3762

63+
templateId := templateResponse.Data.Id
64+
65+
// updateTemplate() {
66+
var newTemplateTitle = "New Title"
67+
var newTemplateDescription = "New Description"
68+
var newFirstNameTitle = "New title for firstName"
69+
var newLastNameDescription = "New description for lastName"
70+
71+
updateRequest := &template.UpdateCredentialTemplateRequest{
72+
Id: templateId,
73+
Title: &newTemplateTitle,
74+
Description: &newTemplateDescription,
75+
Fields: map[string]*template.TemplateFieldPatch{
76+
"firstName": {Title: &newFirstNameTitle},
77+
"lastName": {Description: &newLastNameDescription},
78+
},
79+
FieldOrdering: map[string]*template.FieldOrdering{
80+
"age": {Order: 0, Section: "Misc"},
81+
"firstName": {Order: 1, Section: "Full Name"},
82+
"lastName": {Order: 2, Section: "Full Name"},
83+
},
84+
AppleWalletOptions: &template.AppleWalletOptions{
85+
PrimaryField: "age",
86+
SecondaryFields: []string{"firstName", "lastName"},
87+
},
88+
}
89+
90+
updateResponse, err := trinsic.Template().Update(context.Background(), updateRequest)
91+
// }
92+
93+
if !assert2.Nil(err) && !assert2.NotNil(updateResponse) {
94+
return
95+
}
96+
3897
// issue credential from this template
3998
values := struct {
4099
FirstName string
@@ -93,9 +152,9 @@ func TestTemplatesDemo(t *testing.T) {
93152
}
94153

95154
// updateCredentialStatus() {
96-
updateResponse, err := trinsic.Credential().UpdateStatus(context.Background(), &credential.UpdateStatusRequest{CredentialStatusId: "", Revoked: true})
155+
updateStatusResponse, err := trinsic.Credential().UpdateStatus(context.Background(), &credential.UpdateStatusRequest{CredentialStatusId: "", Revoked: true})
97156
// }
98-
if updateResponse != nil {
157+
if updateStatusResponse != nil {
99158
}
100159

101160
}

0 commit comments

Comments
 (0)