Skip to content

Commit 88d5c77

Browse files
committed
Mirror the v0.1 spec consistency fixes from the canonical VDP repo.
The spec page is now regenerated from VDP/view-descriptor-protocol.md with the site's abbreviation definitions appended, keeping the two copies from drifting.
1 parent d48b999 commit 88d5c77

1 file changed

Lines changed: 48 additions & 38 deletions

File tree

‎docs/specification.md‎

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# View Descriptor Protocol (VDP)
22

33
**Status:** Working Draft
4-
**Version:** 0.1.0
4+
**Version:** 0.1
55

66
## Abstract
77

@@ -49,13 +49,13 @@ When a template has named insertion points that should be filled dynamically, th
4949

5050
```json
5151
{
52-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/layouts/sidebar",
52+
"template": "https://templates.example.com/layouts/sidebar",
5353
"slots": {
5454
"mainContent": {
55-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/card"
55+
"template": "https://templates.example.com/components/data-display/card"
5656
},
5757
"sidebarNav": {
58-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/navigation/nav"
58+
"template": "https://templates.example.com/components/navigation/nav"
5959
}
6060
}
6161
}
@@ -69,29 +69,29 @@ Since each slot value is itself a view descriptor, composition nests to arbitrar
6969

7070
```json
7171
{
72-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/layouts/sidebar",
72+
"template": "https://templates.example.com/layouts/sidebar",
7373
"slots": {
7474
"mainContent": {
75-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/demos/dashboard",
75+
"template": "https://templates.example.com/demos/dashboard",
7676
"slots": {
7777
"statsRow": {
78-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/card"
78+
"template": "https://templates.example.com/components/data-display/card"
7979
},
8080
"activityTable": {
81-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/table"
81+
"template": "https://templates.example.com/components/data-display/table"
8282
},
8383
"chart": {
84-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/charts/chart",
84+
"template": "https://templates.example.com/components/charts/chart",
8585
"slots": {
8686
"legend": {
87-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/charts/chart-legend"
87+
"template": "https://templates.example.com/components/charts/chart-legend"
8888
}
8989
}
9090
}
9191
}
9292
},
9393
"sidebarNav": {
94-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/navigation/nav"
94+
"template": "https://templates.example.com/components/navigation/nav"
9595
}
9696
}
9797
}
@@ -122,29 +122,31 @@ A single API response may offer multiple views (e.g., a summary view and a detai
122122
}
123123
```
124124

125-
When only a single view is needed, the top-level object IS the view descriptor (no `views` wrapper). When multiple views are present, the `views` key wraps them. A client SHOULD use `default` when no specific view is requested.
125+
When only a single view is needed, the top-level object IS the view descriptor (no `views` wrapper). When multiple views are present, the `views` key wraps them.
126+
127+
How a client chooses among named views is out of scope: view names are agreed between server and client out of band, and the client selects based on its own context (device class, container size, user preference, etc.). A client SHOULD use the `default` view when it has no reason to select another. If no `default` view exists and the client has no basis for choosing, it MUST select one of the available views; the choice is client-defined.
126128

127129
### 3.5 Slot Arrays
128130

129131
A single slot can accept multiple templates, rendered in sequence within the insertion point. This is useful when composing multiple independent components into a single region:
130132

131133
```json
132134
{
133-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/layouts/sidebar",
135+
"template": "https://templates.example.com/layouts/sidebar",
134136
"slots": {
135137
"mainContent": [
136138
{
137-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/card"
139+
"template": "https://templates.example.com/components/data-display/card"
138140
},
139141
{
140-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/charts/chart"
142+
"template": "https://templates.example.com/components/charts/chart"
141143
},
142144
{
143-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/table"
145+
"template": "https://templates.example.com/components/data-display/table"
144146
}
145147
],
146148
"sidebarNav": {
147-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/navigation/nav"
149+
"template": "https://templates.example.com/components/navigation/nav"
148150
}
149151
}
150152
}
@@ -208,10 +210,10 @@ When the data format is flexible (e.g., HAL+JSON, custom APIs), embed the view d
208210
"self": { "href": "/api/dashboard" }
209211
},
210212
"_view": {
211-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/demos/dashboard",
213+
"template": "https://templates.example.com/demos/dashboard",
212214
"slots": {
213215
"statsRow": {
214-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/card"
216+
"template": "https://templates.example.com/components/data-display/card"
215217
}
216218
}
217219
},
@@ -266,6 +268,8 @@ When a view descriptor is provided via multiple mechanisms, precedence is:
266268
2. `Link` header with `rel="view-descriptor"`
267269
3. `View-Template` header
268270

271+
If both `_view` and `_views` appear in the same response, `_views` takes precedence and `_view` MUST be ignored.
272+
269273
## 5. View Descriptor Resources
270274

271275
### 5.1 Media Type
@@ -309,10 +313,11 @@ Servers MUST NOT use the media type `version` parameter to version individual vi
309313

310314
### 5.4 URL Resolution
311315

312-
Template URLs in a view descriptor MAY be relative references (RFC 3986 Section 4.2). Clients MUST resolve relative URLs using the following base URL, in order of precedence:
316+
Template URLs in a view descriptor MAY be relative references (RFC 3986 Section 4.2). Clients MUST resolve relative URLs against a base URL determined by the transport that delivered the descriptor:
313317

314318
1. **Standalone view descriptor resource**: The URL of the view descriptor resource itself (i.e., the URL used to fetch it via the `Link` header).
315319
2. **Inline transport** (`_view` / `_views`): The URL of the API response containing the view descriptor.
320+
3. **`View-Template` header**: The URL of the API response carrying the header.
316321

317322
Nested slot template URLs resolve against the same base URL as the root template URL — the base does not change at each nesting level.
318323

@@ -345,10 +350,10 @@ Servers SHOULD use absolute URLs when view descriptors may be consumed by multip
345350

346351
When different clients require different templates (e.g., HTML for web, Compose for Android, SwiftUI for iOS), the server SHOULD use standard HTTP content negotiation to select the appropriate view descriptor. VDP does not define a mechanism for shipping multiple platform variants in a single response — the server selects and returns one view descriptor per request.
347352

348-
Servers MAY use the `Accept` header, custom headers, or query parameters to determine the client's rendering platform:
353+
Negotiation applies to whichever request returns the view descriptor: the fetch of the standalone view descriptor resource (Section 4.1), or the API request itself when the descriptor is inline (Section 4.2). Servers MAY use custom headers or query parameters to determine the client's rendering platform:
349354

350355
```http
351-
GET /api/dashboard HTTP/1.1
356+
GET /views/dashboard.json HTTP/1.1
352357
Accept: application/vdp+json
353358
X-VDP-Platform: android
354359
```
@@ -382,7 +387,7 @@ Not every insertion point in a template needs to appear in the view descriptor.
382387
```http
383388
HTTP/1.1 200 OK
384389
Content-Type: application/json
385-
View-Template: https://github.com/SiteNetSoft/quarkus-pha/templates/components/forms/form
390+
View-Template: https://templates.example.com/components/forms/form
386391
387392
{
388393
"csrfToken": "abc123",
@@ -401,7 +406,7 @@ View-Template: https://github.com/SiteNetSoft/quarkus-pha/templates/components/f
401406
```http
402407
HTTP/1.1 200 OK
403408
Content-Type: application/hal+json
404-
Link: <https://github.com/SiteNetSoft/quarkus-pha/views/dashboard.json>; rel="view-descriptor"
409+
Link: <https://example.com/views/dashboard.json>; rel="view-descriptor"
405410
406411
{
407412
"_links": { "self": { "href": "/api/dashboard" } },
@@ -418,22 +423,22 @@ Link: <https://github.com/SiteNetSoft/quarkus-pha/views/dashboard.json>; rel="vi
418423

419424
```json
420425
{
421-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/layouts/sidebar",
426+
"template": "https://templates.example.com/layouts/sidebar",
422427
"slots": {
423428
"sidebarNav": {
424-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/navigation/nav"
429+
"template": "https://templates.example.com/components/navigation/nav"
425430
},
426431
"mainContent": {
427-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/demos/dashboard",
432+
"template": "https://templates.example.com/demos/dashboard",
428433
"slots": {
429434
"statsCards": {
430-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/card"
435+
"template": "https://templates.example.com/components/data-display/card"
431436
},
432437
"activityTable": {
433-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/data-display/table"
438+
"template": "https://templates.example.com/components/data-display/table"
434439
},
435440
"revenueChart": {
436-
"template": "https://github.com/SiteNetSoft/quarkus-pha/templates/components/charts/chart"
441+
"template": "https://templates.example.com/components/charts/chart"
437442
}
438443
}
439444
}
@@ -529,6 +534,7 @@ When fetching a template URL fails (HTTP 404, 5xx, network error, timeout):
529534
- Clients MUST NOT fail the entire render if a single slot's template is unavailable.
530535
- Clients SHOULD skip the unavailable slot and render the remaining template tree.
531536
- Clients MAY display a placeholder or the template's default slot content in place of the failed slot.
537+
- For slot arrays (Section 3.5), a failed array element is skipped; the remaining elements render in their declared order.
532538
- Clients SHOULD log or report the failure for diagnostic purposes.
533539

534540
### 9.2 Slot Name Mismatch
@@ -557,11 +563,11 @@ Error handling follows the principle that a failure stays as local as possible:
557563

558564
## 10. Security Considerations
559565

560-
- **Template URL validation**: Clients MUST validate template URLs against an allowlist of trusted domains. Rendering arbitrary templates from untrusted sources is a code injection risk.
566+
- **Template URL validation**: Clients MUST validate template URLs against an allowlist of trusted URL prefixes (see `trustedTemplateUrls`, Section 13.2). Rendering arbitrary templates from untrusted sources is a code injection risk.
561567
- **CORS**: Template resources served cross-origin MUST include appropriate CORS headers.
562-
- **Content Security Policy**: Template URLs SHOULD be included in the `script-src` or `style-src` CSP directives as appropriate.
568+
- **Content Security Policy**: Browser clients fetching templates at runtime SHOULD include template origins in the `connect-src` CSP directive. `script-src` or `style-src` apply only where templates are loaded as executable scripts or stylesheets.
563569
- **Template sandboxing**: Clients SHOULD render templates in a sandboxed context to prevent template injection attacks.
564-
- **HTTPS**: Template URLs MUST use HTTPS in production. Clients SHOULD reject HTTP template URLs.
570+
- **HTTPS**: Template URLs MUST use HTTPS. Clients SHOULD reject `http:` template URLs, with an exception permitted for loopback addresses during local development.
565571

566572
## 11. Relationship to Existing Standards
567573

@@ -598,7 +604,7 @@ APIs SHOULD advertise VDP support so clients can detect it programmatically.
598604

599605
### 13.1 OPTIONS Response
600606

601-
An API endpoint supporting VDP MUST advertise it in its `OPTIONS` response, using the `VDP-Support` and `VDP-Version` headers:
607+
An API endpoint supporting VDP SHOULD advertise it in its `OPTIONS` response, using the `VDP-Support` and `VDP-Version` headers:
602608

603609
```http
604610
OPTIONS /api/dashboard HTTP/1.1
@@ -617,7 +623,7 @@ APIs MAY expose a discovery document at `/.well-known/vdp`:
617623
GET /.well-known/vdp HTTP/1.1
618624
619625
HTTP/1.1 200 OK
620-
Content-Type: application/vdp+json
626+
Content-Type: application/json
621627
622628
{
623629
"version": "0.1",
@@ -629,13 +635,17 @@ Content-Type: application/vdp+json
629635
"descriptor": "https://example.com/views/product-list.json"
630636
}
631637
},
632-
"trustedTemplateDomains": [
633-
"https://github.com/SiteNetSoft/quarkus-pha"
638+
"trustedTemplateUrls": [
639+
"https://templates.example.com/"
634640
]
635641
}
636642
```
637643

638-
Each entry in `endpoints` maps an API path to the URL of its view descriptor resource (`descriptor`). This allows clients to prefetch view descriptors and preload templates before making data requests. The `trustedTemplateDomains` field provides the template URL allowlist referenced in Section 10.
644+
The discovery document is not a view descriptor and MUST NOT be served as `application/vdp+json`; it is served as plain `application/json`.
645+
646+
Each entry in `endpoints` maps an API path to the URL of its view descriptor resource (`descriptor`). This allows clients to prefetch view descriptors and preload templates before making data requests.
647+
648+
The `trustedTemplateUrls` field provides the template URL allowlist referenced in Section 10. Each entry is a URL prefix: a template URL is trusted if and only if, after RFC 3986 normalization, it begins with one of the listed entries. Entries SHOULD end with a trailing slash so that `https://templates.example.com/` cannot accidentally match `https://templates.example.com.evil.host/`.
639649

640650
### 13.3 OpenAPI Extension
641651

0 commit comments

Comments
 (0)