Skip to content

Commit 960069e

Browse files
committed
Clarify trailing slash ref-resolution weirdness
There is no way to do RFC 3986 reference resolution that just removes a trailing slash without duplicating things. Every option is confusing and weird, but avoiding trailing slashes is increasingly common. Let's just face that and explain that it's weird and this is the best that can be done.
1 parent b6fd7a0 commit 960069e

File tree

1 file changed

+59
-40
lines changed

1 file changed

+59
-40
lines changed

jsonschema-hyperschema.xml

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
<postamble>
177177
If the instance is {"id": 1234}, and its base URI according to
178178
<xref target="RFC3986">RFC 3986 section 5.1</xref>, is
179-
"https://api.example.com/", then "https://api.example.com/thing/1234"
179+
"https://example.com/api/", then "https://example.com/api/thing/1234"
180180
is the resulting link's target URI.
181181
</postamble>
182182
</figure>
@@ -1551,14 +1551,14 @@ for varname in templateData:
15511551
<section title="Entry Point Links, No Templates" anchor="entryPoint">
15521552
<t>
15531553
For this example, we will assume an example API with a documented
1554-
entry point URI of https://api.example.com, which is an empty JSON object
1554+
entry point URI of https://example.com/api, which is an empty JSON object
15551555
with a link to a schema. Here, the entry point has no data of its
15561556
own and exists only to provide an initial set of links:
15571557
</t>
15581558
<figure>
15591559
<artwork>
15601560
<![CDATA[
1561-
GET https://api.example.com HTTP/1.1
1561+
GET https://example.com/api HTTP/1.1
15621562
15631563
200 OK
15641564
Content-Type: application/json
@@ -1570,23 +1570,22 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
15701570
<t>
15711571
The linked hyper-schema defines the API's base URI and provides
15721572
two links: an "about" link to API documentation, and a "self"
1573-
link indicating that this is a schema for the base URI. In this
1574-
case the base URI is also the entry point URI.
1573+
link indicating that this is a schema for the base URI.
15751574
</t>
15761575
<figure>
15771576
<artwork>
15781577
<![CDATA[
15791578
{
15801579
"$id": "https://schema.example.com/entry",
15811580
"$schema": "http://json-schema.org/draft-08/hyper-schema#",
1582-
"base": "https://api.example.com/",
1581+
"base": "https://example.com/api/",
15831582
"links": [
15841583
{
15851584
"rel": "self",
1586-
"href": ""
1585+
"href": "../api",
15871586
}, {
15881587
"rel": "about",
1589-
"href": "/docs"
1588+
"href": "docs"
15901589
}
15911590
]
15921591
}]]>
@@ -1596,21 +1595,41 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
15961595
These are the simplest possible links, with only a relation type and
15971596
an "href" with no template variables. They resolve as follows:
15981597
</t>
1598+
<t>
1599+
The duplication of "api" in both the base and the "../api"
1600+
href in the "self" link is due to quirks of the RFC 3986
1601+
URI-reference resolution algorithm. In order for relative
1602+
URI-references to work well in general, the base URI needs
1603+
to include a trailing slash. The "about" link with its "docs"
1604+
href shows the common case of relative references, which is
1605+
used in the other examples in this document.
1606+
</t>
1607+
<t>
1608+
However, if an API uses URIs without trailing slashes for its resources,
1609+
there is no way to provide a relative reference that just removes a
1610+
trailing slash without duplicating the path component above it.
1611+
Which makes the case of the entry point resource, which differs
1612+
from the base URI only in terms of the trailing slash, somewhat awkward.
1613+
</t>
1614+
<t>
1615+
Resource URIs, of course, may have trailing slashes, but this example
1616+
is intended to highlight this frequently confusing special case.
1617+
</t>
15991618
<figure>
16001619
<artwork>
16011620
<![CDATA[[
16021621
{
1603-
"contextUri": "https://api.example.com",
1622+
"contextUri": "https://example.com/api",
16041623
"contextPointer": "",
16051624
"rel": "self",
1606-
"targetUri": "https://api.example.com",
1625+
"targetUri": "https://example.com/api",
16071626
"attachmentPointer": ""
16081627
},
16091628
{
1610-
"contextUri": "https://api.example.com",
1629+
"contextUri": "https://example.com/api",
16111630
"contextPointer": "",
16121631
"rel": "about",
1613-
"targetUri": "https://api.example.com/docs",
1632+
"targetUri": "https://example.com/api/docs",
16141633
"attachmentPointer": ""
16151634
}
16161635
]]]>
@@ -1633,7 +1652,7 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
16331652
<![CDATA[{
16341653
"$id": "https://schema.example.com/thing",
16351654
"$schema": "http://json-schema.org/draft-08/hyper-schema#",
1636-
"base": "https://api.example.com/",
1655+
"base": "https://example.com/api/",
16371656
"type": "object",
16381657
"required": ["data"],
16391658
"properties": {
@@ -1830,7 +1849,7 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
18301849
</list>
18311850
</t>
18321851
<t>
1833-
So, given the following instance retrieved from "https://api.example.com/stuff":
1852+
So, given the following instance retrieved from "https://example.com/api/stuff":
18341853
</t>
18351854
<figure>
18361855
<artwork>
@@ -1848,7 +1867,7 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
18481867
<figure>
18491868
<artwork>
18501869
<![CDATA[{
1851-
"contextUri": "https://api.example.com/stuff",
1870+
"contextUri": "https://example.com/api/stuff",
18521871
"contextPointer": "",
18531872
"rel": "author",
18541873
"hrefInputTemplates": [
@@ -1902,14 +1921,14 @@ Link: <https://schema.example.com/entry>; rel="describedBy"
19021921
</preamble>
19031922
<artwork>
19041923
<![CDATA[
1905-
GET https://api.example.com/trees/1/nodes/123 HTTP/1.1
1924+
GET https://example.com/api/trees/1/nodes/123 HTTP/1.1
19061925
19071926
200 OK
19081927
Content-Type: application/json
1909-
Link: <https://api.example.com/trees/1/nodes/123>; rel="self"
1910-
Link: <https://api.example.com/trees/1/nodes/123>; rel="up";
1911-
anchor="https://api.example.com/trees/1/nodes/456"
1912-
Link: <https://api.example.com/trees/1/nodes/456>; rev="up"
1928+
Link: <https://example.com/api/trees/1/nodes/123>; rel="self"
1929+
Link: <https://example.com/api/trees/1/nodes/123>; rel="up";
1930+
anchor="https://example.com/api/trees/1/nodes/456"
1931+
Link: <https://example.com/api/trees/1/nodes/456>; rev="up"
19131932
{
19141933
"id": 123,
19151934
"treeId": 1,
@@ -1998,7 +2017,7 @@ Link: <https://api.example.com/trees/1/nodes/456>; rev="up"
19982017
<![CDATA[{
19992018
"$id": "https://schema.example.com/thing",
20002019
"$schema": "http://json-schema.org/draft-08/hyper-schema#",
2001-
"base": "https://api.example.com/",
2020+
"base": "https://example.com/api/",
20022021
"type": "object",
20032022
"required": ["data"],
20042023
"properties": {
@@ -2051,7 +2070,7 @@ Link: <https://api.example.com/trees/1/nodes/456>; rev="up"
20512070
<![CDATA[{
20522071
"$id": "https://schema.example.com/thing-collection",
20532072
"$schema": "http://json-schema.org/draft-08/hyper-schema#",
2054-
"base": "https://api.example.com/",
2073+
"base": "https://example.com/api/",
20552074
"type": "object",
20562075
"required": ["elements"],
20572076
"properties": {
@@ -2104,52 +2123,52 @@ Link: <https://api.example.com/trees/1/nodes/456>; rev="up"
21042123
<artwork>
21052124
<![CDATA[[
21062125
{
2107-
"contextUri": "https://api.example.com/things",
2126+
"contextUri": "https://example.com/api/things",
21082127
"contextPointer": "",
21092128
"rel": "self",
2110-
"targetUri": "https://api.example.com/things",
2129+
"targetUri": "https://example.com/api/things",
21112130
"attachmentPointer": ""
21122131
},
21132132
{
2114-
"contextUri": "https://api.example.com/things",
2133+
"contextUri": "https://example.com/api/things",
21152134
"contextPointer": "/elements/0",
21162135
"rel": "self",
2117-
"targetUri": "https://api.example.com/things/12345",
2136+
"targetUri": "https://example.com/api/things/12345",
21182137
"attachmentPointer": "/elements/0"
21192138
},
21202139
{
2121-
"contextUri": "https://api.example.com/things",
2140+
"contextUri": "https://example.com/api/things",
21222141
"contextPointer": "/elements/1",
21232142
"rel": "self",
2124-
"targetUri": "https://api.example.com/things/67890",
2143+
"targetUri": "https://example.com/api/things/67890",
21252144
"attachmentPointer": "/elements/1"
21262145
},
21272146
{
2128-
"contextUri": "https://api.example.com/things",
2147+
"contextUri": "https://example.com/api/things",
21292148
"contextPointer": "",
21302149
"rel": "item",
2131-
"targetUri": "https://api.example.com/things/12345",
2150+
"targetUri": "https://example.com/api/things/12345",
21322151
"attachmentPointer": "/elements/0"
21332152
},
21342153
{
2135-
"contextUri": "https://api.example.com/things",
2154+
"contextUri": "https://example.com/api/things",
21362155
"contextPointer": "",
21372156
"rel": "item",
2138-
"targetUri": "https://api.example.com/things/67890",
2157+
"targetUri": "https://example.com/api/things/67890",
21392158
"attachmentPointer": "/elements/1"
21402159
},
21412160
{
2142-
"contextUri": "https://api.example.com/things",
2161+
"contextUri": "https://example.com/api/things",
21432162
"contextPointer": "/elements/0",
21442163
"rel": "collection",
2145-
"targetUri": "https://api.example.com/things",
2164+
"targetUri": "https://example.com/api/things",
21462165
"attachmentPointer": "/elements/0"
21472166
},
21482167
{
2149-
"contextUri": "https://api.example.com/things",
2168+
"contextUri": "https://example.com/api/things",
21502169
"contextPointer": "/elements/1",
21512170
"rel": "collection",
2152-
"targetUri": "https://api.example.com/things",
2171+
"targetUri": "https://example.com/api/things",
21532172
"attachmentPointer": "/elements/1"
21542173
}
21552174
]]]>
@@ -2310,19 +2329,19 @@ Link: <https://api.example.com/trees/1/nodes/456>; rev="up"
23102329
<artwork>
23112330
<![CDATA[[
23122331
{
2313-
"contextUri": "https://api.example.com/things",
2332+
"contextUri": "https://example.com/api/things",
23142333
"contextPointer": "",
23152334
"rel": "self",
23162335
"targetUri":
2317-
"https://api.example.com/things?offset=0&limit=2",
2336+
"https://example.com/api/things?offset=0&limit=2",
23182337
"attachmentPointer": ""
23192338
},
23202339
{
2321-
"contextUri": "https://api.example.com/things",
2340+
"contextUri": "https://example.com/api/things",
23222341
"contextPointer": "",
23232342
"rel": "next",
23242343
"targetUri":
2325-
"https://api.example.com/things?offset=3&limit=2",
2344+
"https://example.com/api/things?offset=3&limit=2",
23262345
"attachmentPointer": ""
23272346
}
23282347
]]]>

0 commit comments

Comments
 (0)