Skip to content

Commit 5437e77

Browse files
committed
URI Template resolution as pseudocode
This consolidates all of the URI Template resolution sections into one section. The new section is at the top level, as it applies to both LDO keywords ("href", "anchor", and all of the algorithm modifiers) and to a schema keyword ("base"). As much of the algorithm as possible is now given in pseudocode, although whether this is the most readable form is debatable. It is certainly more concise, and forced detailed consideration of some steps which had been under-specified, particularly with respect to "hrefSchema". The main change is that the input data for "hrefSchema" is prepopulated only with instance data that validates against all applicable subschemas within "hrefSchema". Expressing this properly requires the "applicability" concept from PR json-schema-org#424. Previously, the only mention of how to exclude a field from being used to pre-populate input was the advice to set the "properties" subschema to "false". However, this does not hold up once you start using more complex schemas.
1 parent 884b964 commit 5437e77

File tree

1 file changed

+137
-164
lines changed

1 file changed

+137
-164
lines changed

jsonschema-hyperschema.xml

Lines changed: 137 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -353,60 +353,6 @@
353353
at runtime, for instance due to application state that controls the operation's
354354
availability.
355355
</t>
356-
<section title="Resolving templated URIs">
357-
<t>
358-
URI Template variables in <xref target="href">"href"</xref> resolve from
359-
server-supplied instance data by default. This data is drawn from the
360-
sub-instance that validated against the schema containing the LDO.
361-
</t>
362-
<t>
363-
<xref target="templatePointers">"templatePointers"</xref> allows adjusting
364-
the location from which instance data is resolved on a per-variable
365-
basis.
366-
</t>
367-
<t>
368-
<xref target="hrefSchema">"hrefSchema"</xref> allows a link to specify
369-
a schema for resolving template variables from client-supplied data.
370-
Regular JSON Schema validation features can be used to require resolution
371-
from user agent data, forbid it, or allow user agent data while falling back
372-
to server-supplied instance data if no user agent data is provided.
373-
</t>
374-
<t>
375-
To implement the common pattern of resolving a templated path component
376-
with server-supplied instance data while accepting user agent data to build
377-
a query string:
378-
<list style="symbols">
379-
<t>
380-
set the "hrefSchema" subschemas for the path template variables
381-
to false, to disallow user agent input
382-
</t>
383-
<t>
384-
give the query string template variables names that do not appear
385-
in the instance, to prevent resolving them from the instance
386-
</t>
387-
</list>
388-
See the "hrefSchema" section for an example of this approach.
389-
</t>
390-
<t>
391-
To implement the equivalent of an input form pre-populated with
392-
pre-existing instance data:
393-
<list style="symbols">
394-
<t>
395-
ensure that each variable in the form resolves from the appropriate
396-
field in the instance, which provides the initial value that will
397-
continue to be used if the user agent takes no action to change it
398-
</t>
399-
<t> provide a validation schema for each of those fields in
400-
"hrefSchema", to describe what user agent input may be allowed
401-
to replace it
402-
</t>
403-
</list>
404-
This can be done with variables in any component of the URI template
405-
(path, query string, etc.) While the word "form" is used here,
406-
JSON Hyper-Schema does not constraint the nature of this interaction, which
407-
may or may not involve rendering an interactive form.
408-
</t>
409-
</section>
410356
<section title="Manipulating the target resource representation">
411357
<t>
412358
In JSON Hyper-Schema, <xref target="targetSchema">"targetSchema"</xref>
@@ -451,112 +397,6 @@
451397
This property is REQUIRED.
452398
</t>
453399

454-
<section title="URI Templating">
455-
<t>
456-
<cref>
457-
The pre-processing rules present in earlier drafts have been removed due
458-
to their complexity and inability to address all limitations with URI
459-
templating.
460-
This section is subject to significant change in upcoming drafts to
461-
replace the old pre-processing with a comprehensive solution.
462-
</cref>
463-
</t>
464-
<t>
465-
The value of "href" is to be used as a URI Template, as defined in
466-
<xref target="RFC6570">RFC 6570</xref>.
467-
However, some special considerations apply:
468-
</t>
469-
470-
<section title="Values for substitution">
471-
<t>
472-
The URI Template is filled out using data from some combination of an
473-
external source and the instance.
474-
Where either instance data or user agent data may be used, this section
475-
will refer simply to "data" or to a "value".
476-
When the source is important, it is specified explicitly.
477-
478-
To allow the use of any object property (including the empty string) or
479-
array index, the following rules are defined:
480-
</t>
481-
482-
<t>
483-
For a given variable name in the URI Template, the value to use is
484-
determined as follows:
485-
<list>
486-
<t>
487-
If the data is an array, and the variable name is a
488-
representation of a non-negative integer, then the value at the
489-
corresponding array index MUST be used (if it exists).
490-
</t>
491-
<t>
492-
Otherwise, the variable name should be percent-decoded, and the
493-
corresponding object property MUST be used (if it exists).
494-
</t>
495-
</list>
496-
</t>
497-
498-
<t>
499-
If <xref target="hrefSchema">"hrefSchema"</xref> is present and
500-
user agent data is provided, the data MUST be a valid instance according
501-
to the value of "hrefSchema".
502-
Template variables, after the process listed above, MUST first
503-
be resolved from the user agent data instance. Any variables left
504-
unresolved MUST be resolved from the resource instance data.
505-
</t>
506-
507-
<section title="Converting to strings">
508-
<t>
509-
When any value referenced by the URI template is null, a boolean or
510-
a number, then it should first be converted into a string as
511-
follows:
512-
<list>
513-
<t>
514-
null values SHOULD be replaced by the text "null"
515-
</t>
516-
<t>
517-
boolean values SHOULD be replaced by their lower-case
518-
equivalents: "true" or "false"
519-
</t>
520-
<t>
521-
numbers SHOULD be replaced with their original JSON
522-
representation.
523-
</t>
524-
</list>
525-
</t>
526-
<t>
527-
In some software environments the original JSON representation of a
528-
number will not be available (there is no way to tell the difference
529-
between 1.0 and 1), so any reasonable representation should be used.
530-
Schema and API authors should bear this in mind, and use other types
531-
(such as string or boolean) if the exact representation is
532-
important.
533-
</t>
534-
</section>
535-
</section>
536-
537-
<section title="Missing values" anchor="missingValues">
538-
<t>
539-
Sometimes, the appropriate values will not be available. In many
540-
cases, the URI Template behavior of simply removing variables that
541-
do not have a value will be appropriate. An example of this is
542-
optional query parameters, the presence or absence of which does
543-
not change the nature of the link relation type.
544-
</t>
545-
546-
<t>
547-
However, some variables, such as an identifier used in a path component,
548-
cannot meaningfully be omitted. The resulting URI would be meaningless,
549-
or would require a different link relation type. While "hrefSchema" can
550-
express a requirement for those variables that can be supplied via input,
551-
some variables must be resolved from instance data. When that instance
552-
data is not required by the context schema, the
553-
<xref target="templateRequired">"templateRequired</xref> keyword may
554-
be used to indicate that when the instance data is not available, the
555-
link does not apply.
556-
</t>
557-
</section>
558-
</section>
559-
560400
</section>
561401

562402
<section title="templatePointers" anchor="templatePointers">
@@ -676,11 +516,22 @@
676516
any user agent data from being accepted.
677517
</t>
678518
<t>
679-
Implementations MUST NOT attempt to validate values resolved from
680-
resource instance data with "hrefSchema". This allows for different
519+
For template variables that can be resolved from the instance, if
520+
the variable is NOT:
521+
<list style="symbols">
522+
<t>Present in "properties" with a value of false, OR</t>
523+
<t>Matching a key in "patternProperties" with a value of false, OR</t>
524+
<t>Matched by "additionalProperties" with a value of false</t>
525+
</list>
526+
then the input data set for that variable SHOULD be pre-populated
527+
with the value from the instance.
528+
</t>
529+
<t>
530+
Note that even when data is pre-populated from the instance, the validation
531+
schema for that variable in "hrefSchema" need not match the validation
532+
schema(s) that apply to the instance data's location. This allows for different
681533
validation rules for user agent data, such as supporting spelled-out
682-
months for date-time input but using the standard date-time
683-
format for storage.
534+
months for date-time input, but using the standard date-time format for storage.
684535
</t>
685536
<figure>
686537
<preamble>
@@ -1539,6 +1390,128 @@ GET /foo/
15391390
</t>
15401391
</section>
15411392
</section>
1393+
<section title="URI Templating">
1394+
<t>
1395+
Three hyper-schema keywords are <xref target="RFC6570">URI Templates</xref>:
1396+
"base", "anchor", and "href". Each are resolved separately to URI-references,
1397+
and then the anchor or href URI-reference is resolved against the base (which
1398+
is itself resolved against earlier bases as needed, each of which was first
1399+
resolved from a URI Template to a URI-reference).
1400+
</t>
1401+
<t>
1402+
All three keywords share the same algorithm for resolving variables from
1403+
instance data, which makes use of the "templatePointers" and "templateRequired"
1404+
keywords. When resolving "href", both it and any "base" templates
1405+
needed for resolution to an absolute URI, the algorithm is modfied to
1406+
optionally accept user input based on the "hrefSchema" keyword.
1407+
</t>
1408+
<t>
1409+
For each URI Template (T), the following pseudocode describes an algorithm for
1410+
resolving T into a URI-reference (R). For the purpose of this algorithm:
1411+
<list style="symbols">
1412+
<t>
1413+
"ldo.templatePointers" is an empty object if the keyword was not
1414+
present and "ldo.templateRequired" is likewise an empty array.
1415+
</t>
1416+
<t>
1417+
"attachmentPointer" is the absolute JSON Pointer for the attachment
1418+
location of the LDO.
1419+
</t>
1420+
<t>
1421+
"getApplicableSchemas()" returns an iterable set of all (sub)schemas
1422+
that apply to the attachment point in the instance.
1423+
</t>
1424+
<t>
1425+
"InputForm" represents whatevers sort of input mechanism is appropriate.
1426+
This may be a literal web form, or may be a more programmatic construct
1427+
such as a callback funciton accepting specific fields and data types,
1428+
with the given initial values, if any.
1429+
</t>
1430+
</list>
1431+
</t>
1432+
<figure>
1433+
<preamble>
1434+
This algorithm should be applied first to either "href" or "anchor",
1435+
and then as needed to each successive "base". The order is important,
1436+
as it is not always possible to tell whether a template will resolve
1437+
to a full URI or a URI-reference.
1438+
</preamble>
1439+
<artwork>
1440+
<![CDATA[
1441+
templateData = {}
1442+
1443+
for varname in T:
1444+
varname = rfc3986PercentDecode(varname)
1445+
if varname in ldo.templatePointers:
1446+
valuePointer = templatePointers[varname]
1447+
if valuePointer is relative:
1448+
valuePointer = resolveRelative(attachmentPointer,
1449+
valuePointer)
1450+
else
1451+
valuePointer = attachmentPointer + "/" + varname
1452+
1453+
value = instance.valueAt(valuePointer)
1454+
if value is defined:
1455+
templateData[varname] = value
1456+
1457+
if resolving "href" and ldo.hrefSchema exists:
1458+
1459+
form = new InputForm()
1460+
for varname in T:
1461+
usable = true
1462+
for schema in getApplicableSchemas(ldo.hrefSchema,
1463+
"/" + varname):
1464+
if schema is false or (
1465+
varname in templateData and
1466+
not isValid(templateData[varname], schema)):
1467+
1468+
usable = false
1469+
break
1470+
1471+
if usable:
1472+
form.addInputFieldFor(ldo.hrefSchema,
1473+
varname,
1474+
templateData[varname])
1475+
inputData = form.acceptInput()
1476+
1477+
if not validate(inputData, hrefSchema):
1478+
fatal("Input invalid, link is not usable")
1479+
1480+
for varname in inputData:
1481+
templateData[varname] = inputData[varname]
1482+
1483+
for varname in ldo.templateRequired:
1484+
if not exists templateData[varname]
1485+
fatal("Missing required variable(s)")
1486+
1487+
for varname in templateData:
1488+
value = templateData[varname]
1489+
if value is true:
1490+
templateData[varname] = "true"
1491+
else if value is false:
1492+
temlateData[varname] = "false"
1493+
else if value is null:
1494+
templateData[varname] = "null"
1495+
else if value is a number:
1496+
templateData[varname] =
1497+
bestEffortOriginalJsonString(value)
1498+
else:
1499+
templateData[varname] = rfc3986PercentEncode(value)
1500+
1501+
let R = rfc6570ResolutionAlgorithm(T, templateData)
1502+
]]>
1503+
</artwork>
1504+
<postamble>
1505+
In some software environments the original JSON representation of a
1506+
number will not be available (there is no way to tell the difference
1507+
between 1.0 and 1), so any reasonable representation should be used.
1508+
Schema and API authors should bear this in mind, and use other types
1509+
(such as string or boolean) if the exact representation is
1510+
important. If the number was provide as input in the form of a
1511+
string, the string used as input SHOULD be used.
1512+
</postamble>
1513+
</figure>
1514+
</section>
15421515

15431516
<!--
15441517
<section title="IANA Considerations">

0 commit comments

Comments
 (0)