-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathindex.bs
6265 lines (5995 loc) · 208 KB
/
index.bs
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class='metadata'>
Title: Hydra Core Vocabulary
Shortname: hydra
Level: 1
Status: LD
Group: HydraCG
URL: https://www.hydra-cg.com/spec/latest/core/
!Author: Markus Lanthaler
!Author: Karol Szczepanski
Editor: Markus Lanthaler
Editor: Karol Szczepanski
Abstract: Hydra is a lightweight vocabulary to create hypermedia-driven Web APIs. By specifying a number of concepts commonly used in Web APIs it enables the creation of generic API clients.
Markup Shorthands: markdown yes
Markup Shorthands: dfn yes
Line Numbers: yes
</pre>
<style type="text/css">
.example > .marker { text-transform: none; }
table.def th { width: 8em; }
.warning {
margin: 1em auto;
padding: 0.5em;
border: 0.5em;
border-left-style: solid;
page-break-inside: avoid;
border-color: #ff0000;
background: #fbe9e9;
background: var(--note-bg);
color: black;
color: var(--note-text);
overflow: auto;
</style>
Status of This Document {#sotd}
=======================
This specification was published by the [[!HydraCG]].
It is not a W3C Standard, nor it is on the W3C Standards Track.
Please note that under the
*W3C Community Contributor License Agreement (CLA)*
there is a limited opt-out and other conditions apply.
Learn more about *W3C Community and Business Groups*.
## Conventions ## {#conventions}
Within this document, the following namespace prefix bindings are used:
<table class="def">
<tr>
<th>Prefix</th>
<th>Namespace</th>
</tr>
<tr>
<td>hydra:</td>
<td>http://www.w3.org/ns/hydra/core#</td>
</tr>
<tr>
<td>rdf:</td>
<td>http://www.w3.org/1999/02/22-rdf-syntax-ns#</td>
</tr>
<tr>
<td>rdfs:</td>
<td>http://www.w3.org/2000/01/rdf-schema#</td>
</tr>
<tr>
<td>xsd:</td>
<td>http://www.w3.org/2001/XMLSchema#</td>
</tr>
<tr>
<td>owl:</td>
<td>http://www.w3.org/2002/07/owl#</td>
</tr>
<tr>
<td>vs:</td>
<td>http://www.w3.org/2003/06/sw-vocab-status/ns#</td>
</tr>
<tr>
<td>dc:</td>
<td>http://purl.org/dc/terms/</td>
</tr>
<tr>
<td>cc:</td>
<td>http://creativecommons.org/ns#</td>
</tr>
<tr>
<td>schema:</td>
<td>http://schema.org/</td>
</tr>
</table>
Introduction {#introduction}
============
Note: This section is non-normative.
Coping with the ever-increasing amount of data becomes increasingly
challenging. To alleviate the information overload put on people,
systems are progressively being connected directly to each other.
They exchange, analyze, and manipulate humongous amounts of data
without any human interaction. Most current solutions, however,
do not exploit the whole potential of the architecture of the World
Wide Web and completely ignore the possibilities offered by Linked Data
technologies.
The combination of the REST architectural style, and the Linked
Data principles offer opportunities to advance the Web of machines
in a similar way that hypertext did for the human Web. Most
building blocks exist already and are in place, but they are rarely
used together. Hydra tries to fill that gap. It allows data
to be enriched with machine-readable affordances which enable interaction.
This not only addresses the problem that Linked Data is still mostly
read-only, but it also paves the way for a completely new breed
of interoperable Web APIs. The fact that it enables the creation
of composable contracts means that interaction models of Web APIs
can be reused at an unprecedented granularity.
Hydra at a Glance {#hydra-at-a-glance}
=================
Note: This section is non-normative.
The basic idea behind Hydra is to provide a vocabulary which enables a
server to advertise valid state transitions to a client. A client can
then use this information to construct requests (i.e. compliant with
an HTTP protocol) which modify the server’s state so that a certain
desired goal is achieved. Since all the information about the valid state
transitions is exchanged in a machine-processable way at runtime
instead of being hardcoded into the client at design time, clients
can be decoupled from the server and adapt to changes more easily.
The namespace of the Hydra core vocabulary
is `http://www.w3.org/ns/hydra/core#`, and the suggested prefix
is `hydra`. The figure below illustrates the vocabulary
(the figure’s goal is to show how Hydra is used rather than its precise
definition).
<img src="vocabulary.png" alt="The Hydra core vocabulary">
An alphabetical index of the classes and properties of Hydra
is given below. All the terms are hyperlinked to their detailed
description for quick reference.
Using Hydra {#using-hydra}
===========
Throughout this section, a simple Web API featuring an issue tracker
will be used to illustrate how Hydra can be used. The Web API enables
its users to file new issues, modify or delete existing ones, and
to comment them. For the sake of simplicity, orthogonal aspects such
as authentication or authorization are not covered.
## Adding Affordances to Representations ## {#adding-affordances-to-representations}
The exemplary Web API has to expose representations of issues and
comments. To enable interaction with those resources, a client has
to know which operations the server supports. In human-facing
websites such affordances are typically exposed by links and forms
and described in natural language. Unfortunately, machines can not
interpret such information easily. The solution that presents itself
is to reduce the language to a few unambiguous concepts which are easily
recognizable by a machine client. Hydra formalizes such concepts.
The simplest and most important affordance on the Web are hyperlinks.
Without them, it would be impossible to browse the Web.
Users typically select the link based on the text it is labeled with.
To give machines a similar understanding, links can be annotated
with a link relation type—a registered token or a URI identifying
the semantics of the link. The following example shows how such
a typed link is used in HTML to reference a stylesheet.
<div class="example" heading="A typed link referencing a stylesheet as used in HTML">
<xmp highlight="html" line-highlight="2">
<link href="http://www.example.com/styles.css"
rel="stylesheet" />
</xmp>
</div>
In Linked Data, the link relation type corresponds to the property itself.
An example in JSON-LD would thus look as follows.
<div class="example" heading="Referencing a stylesheet in JSON-LD">
<pre highlight="json-ld" line-highlight="2">
{
"urn:iana:link-relations:stylesheet": {
"@id": "http://www.example.com/styles.css"
}
}
</pre>
</div>
Generally, a client decides whether to follow a link or not based on
the link relation (or property in the case of Linked Data) which
defines its semantics. There are however also clients such as Web crawlers
which simply follow every link intended to be dereferenced. In HTML this
usually means that all links in anchor elements
(the <a> tag) are followed, but most references in link
elements (the <link> tag), such as used in the example
above, are ignored. Since in RDF serializations no such distinction exists,
the best a client can do is to blindly try to dereference all URIs.
It would thus be beneficial to describe in a machine-readable manner
if a property represents a link intended to be dereferenced or
solely an identifier. Hydra's [=Link=] class does just that. It can be
used to define properties that represent dereferencable links.
In the exemplary Web API used throughout this section, it can be
used to define a property linking issues to their comments:
<div class="example" heading="Defining properties representing hyperlinks using Hydra's Link class">
<pre highlight="json-ld" line-highlight="4">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/vocab#comments",
"@type": "Link"
}
</pre>
</div>
In the example above, a property identified with the URL
`http://api.example.com/vocab#comments` is defined to be
of the type [=Link=]. This is enough information for a client understanding
Hydra to know that the value of the `comments` property
in the following example is intended to be dereferenced.
Note: It is recommended to dereference resources that are within an API's domain.
This may prevent possible issues with cross-site scripting or obtaining
resources which might have no meaning to the client or such that the client
would be unable to interpret. Still, there is no formal prohibition of
dereferencing resources linked with well-known properties, e.g.
*rdf:seeAlso*.
<div class="example" heading="Using a property defined to be a hyperlink">
<pre highlight="json-ld" line-highlight="3,7">
{
"@context": {
"comments": "http://api.example.com/vocab#comments"
},
"@id": "http://api.example.com/an-issue",
"title": "An exemplary issue linking to its comments",
"comments": { "@id": "http://api.example.com/an-issue/comments" }
}
</pre>
</div>
In the example above, the value of the `comments` property
is a JSON object with an `@id` member. This is JSON-LD's
convention to distinguish between strings and IRIs. By using JSON-LD's
type-coercion feature, the representation can be made even more idiomatic:
<div class="example" heading="Using JSON-LD's type-coercion feature to create idiomatic representations">
<pre highlight="json-ld" line-highlight="5,11">
{
"@context": {
"comments": {
"@id": "http://api.example.com/vocab#comments",
"@type": "@id"
}
},
"@id": "http://api.example.com/an-issue",
"title": "An exemplary issue linking to its comments",
"comments":
"http://api.example.com/an-issue/comments"
}
</pre>
</div>
While links are enough to build read-only Web APIs, more powerful
affordances are required to build read-write Web APIs. Thus, Hydra
introduces the notion of operations. Simply speaking, an
[=Operation=] represents the information necessary for a client
to construct valid HTTP requests in order to manipulate the server's
resource state. As such, the only required property of an
[=Operation=] is its [=method=]. Optionally, it is also possible
to describe what information the server [=expects=] or [=returns=],
including additional information about response status codes that
might be returned. This helps a developer to understand what to expect
when invoking an operation. This information has, however,
not to be considered as being complete; it is merely a hint.
Developers should, e.g., expect that other status codes might be returned
and program their clients accordingly.
The following example illustrates how representations can be
augmented with information that enables clients to interact with
them.
<div class="example" heading="A representation of an issue augmented with a delete operation">
<pre highlight="json-ld" line-highlight="2,6-11">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "/an-issue",
"title": "An exemplary issue representation",
"description": "This issue can be deleted with an HTTP DELETE request.",
"operation": [
{
"@type": "Operation",
"method": "DELETE"
}
]
}
</pre>
</div>
The example above references Hydra's context to map properties such
as [=operation=] and [=method=] and values like [=Operation=] to URLs
that unambiguously identify these concepts. It would be similarly valid
JSON-LD if these mappings would be directly embedded into the representation
or if the full URLs would be used instead. Typically, however, the context
is the same for a lot of representations in a Web API and it thus makes
sense to reduce the response size by leveraging a remote context that
can easily be cached by a client.
Note: It is worth mentioning that due to the fact that Hydra is built on
RDF, which is a graph, it may happen that a related resource
(an object of the relation) may not be fully described in the
resource's payload.
In several circumstances (i.e. payload terms defined in
[=ApiDocumentation|API documentation=] sa described in
[[#documenting-a-web-api]] or [=IriTemplate=]
expected as a related resource as described in
[[#templated-links|Templated Links]]) client may
discover no additional statements describing it. These rules should
be considered by the client in following scenarios:
- in case of an object expected to be a hypermedia resource does not have
all the necessary statements for which it is a subject, the client
SHOULD look in the [=ApiDocumentation|API documentation=] for more details
- in case the mentioned object, after consulting
an [=ApiDocumentation|API documentation=], still does not have
all the necessary statements for which it is a subject and both
mentioned object's Url and Url of the initially obtained resource
has the same scheme and authority (by means of [[!RFC3986]]
sections 3.1 and 3.2), the client SHOULD dereference that URL.
If the resource does not have the same scheme and authority the client
MAY chose to dereference it (for example if the resource originates
from another API well-known to the client)
- in case the mentioned object still does not have all the necessary
statements for which it is a subject (i.e. dereferencing it failed
or statements are missing), the client SHOULD either ignore the whole
statement (i.e. for display purposes) or throw an exception
(i.e. an [=IriTemplate=] is about to be resolved and dereferenced)
Example of each of the situations are as follows:
<div class="example" heading="IriTemplate details extraction">
<xmp highlight="http">
HTTP/1.1 200 OK
Content-Type: application/ld+json
Link: <http://api.example.com/doc/>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@graph": [{
"@id": "http://api.example.com/attachments",
"@type": "hydra:Collection",
"api:attachmentByIssue": "api:AttachmentByIssueTemplate"
}, {
"@id": "http://api.example.com/issues",
"@type": "hydra:Collection",
"api:issueByName": "api:IssueByNameTemplate"
}
}
</xmp>
<pre highlight="http">
HTTP/1.1 200 OK
Content-Type: application/ld+json
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@graph": [{
"@id": "api:AttachmentByIssueTemplate",
"@type": "hydra:IriTemplate",
"template": "http://api.example.com/attachments/{issue}",
...
}]
}
</pre>
</div>
where:
- resource `http://api.example.com/attachments` should have
an [=IriTemplate=] available as there is a complete definition
of the template available at `http://api.example.com/doc/`
- resource `http://api.example.com/issues` should not have
an IRI template exposed as there are no additional details available,
neither in the initial resources' payload nor in the API documentation
Note: Keep in mind that any resource described by any hypermedia control
may fail at runtime due to various reasons. Operation details
such as [=returns=] or [=possibleStatus=] may also vary at runtime,
which means client SHOULD always verify received payloads at runtime.
## Documenting a Web API ## {#documenting-a-web-api}
In Web APIs, most representations are typically very similar.
Furthermore, resources often support the same operations. It thus
makes sense, to collect this information in a central documentation.
Traditionally, this has been done in natural language which forces
developers to hardcode that knowledge into their clients. Hydra
addresses this issue by making the documentation completely
machine-processable. The fact that all definitions can be identified
by URLs enables reuse at unprecedented granularity.
Hydra's [=ApiDocumentation=] class builds the foundation for
the description of a Web API. As shown in the following example,
Hydra describes an API by giving it a title, a short description, and
documenting its main entry point. Furthermore, the classes known to
be supported by the Web API and additional information about status
codes that might be returned can be documented. This information
may be used to automatically generate documentations in natural
language.
<div class="example" heading="The overall structure of a Hydra API documentation">
<pre highlight="json-ld" line-highlight="4-12">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/",
"@type": "ApiDocumentation",
"title": "The name of the API",
"description": "A short description of the API",
"entrypoint": "URL of the API's main entry point",
"supportedClass": [
// "... Classes known to be supported by the Web API ..."
],
"possibleStatus": [
// "... Statuses that should be expected and handled properly ..."
]
}
</pre>
</div>
In Linked Data, properties are, just as everything else, identified
by IRIs and thus have global scope which implies that they have
independent semantics. In contrast, properties in data models as
used in common programming languages are class-dependent. Their
semantics depend on the class they belong to. In data models classes
are typically described by the properties they expose whereas in
Linked Data properties define to which classes they belong. If no
class is specified, it is assumed that a property may apply to every
class.
These differences have interesting consequences. For example, the
commonly asked question of which properties can be applied to an
instance of a specific class can typically not be answered for
Linked Data. Strictly speaking, any property which is not explicitly
forbidden could be applied. This stems from the fact that Linked Data
works under an open-world assumption whereas data models used by
programmers typically work under a closed-world assumption. The
difference is that when a closed world is assumed, everything that
is not known to be true is false or vice-versa. With an open-world
assumption the failure to derive a fact does not automatically imply
the opposite; it embraces the fact that the knowledge is incomplete.
Since Hydra may use classes to describe the information expected or
returned by an operation, it also defines a concept to describe the
properties known to be supported by a class. The following example
illustrates this feature. Instead of referencing properties directly,
[=supportedProperty=] references an intermediate data structure,
namely instances of the [=SupportedProperty=] class. This makes
it possible to define whether a specific property is required or
whether it is read-only or write-only depending on the class it is
associated with.
<div class="example" heading="Defining a class and documenting its supported properties">
<pre highlight="json-ld" line-highlight="3-16">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#Comment",
"@type": "Class",
"title": "The name of the class",
"description": "A short description of the class.",
"supportedProperty": [
// "... Properties known to be supported by the class ..."
{
"@type": "SupportedProperty",
"property": "#property", // "The property"
"required": true, // "Is the property required in a request to be valid?"
"readable": false, // "Can the client retrieve the property's value?"
"writable": true // "Can the client change the property's value?"
}
]
}
</pre>
</div>
All instances of a specific class typically support the same operations.
Hydra therefore features a [=supportedOperation=] property which defines
the operations supported by all instances of a class.
<div class="example" heading="Defining a class and documenting its supported operations">
<pre highlight="json-ld" line-highlight="4,10-12">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#Comment",
"@type": "Class",
"title": "The name of the class",
"description": "A short description of the class.",
"supportedProperty": [
// "... Properties known to be supported by the class ..."
],
"supportedOperation": [
// "... Operations known to be supported by instances of the class ..."
]
}
</pre>
</div>
The same feature can be used to describe the operations supported
by values of a [=Link=] property. This is often helpful when
certain operations depend on the permissions of the current user. It
makes it, e.g., possible to show a "delete" link only if the current
user has the permission to delete the resource. Otherwise, the link
would simply be hidden in the representation.
Example shown below describes the operation's expected and returned
value as a dereferencable resource (an RDF resource of a given class),
but the vocabulary is not limited to only those originating
from RDF and is enabled to other types of resources.
Please note that in case of multiple either returned or expected types
provided, client SHOULD assume the set includes any of the types,
but not limited to those types and client SHOULD interpret a received
payload at runtime for possible discrepancies.
<div class="example" heading="Documenting the supported operations of link properties">
<pre highlight="json-ld" line-highlight="4,7-18">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#comments",
"@type": "Link",
"title": "Comments",
"description": "A link to comments with an operation to create a new comment.",
"supportedOperation": [
{
"@type": "Operation",
"title": "Creates a new comment",
"method": "POST",
"expects": "http://api.example.com/doc/#Comment",
"returns": "http://api.example.com/doc/#Comment",
"possibleStatus": [
// "... Statuses that should be expected and handled properly ..."
]
}
]
}
</pre>
</div>
Note: It is worth to mention that Hydra comes with a notion
of a dereferenceability promise, which means that resources marked
with a [=Resource=] class can be safely dereferenced by a client.
Unfortunately, the way how the Word Wide Web works it is impossible to
guarantee that the resource finally will be obtained.
In addition to [=expects|expected=]/[=returns|returned=] resources,
it is also possible to express similar features for headers with
[=returnsHeader=] and [=expectsHeader=] predicates which provides
a simple set of header names. Client SHOULD apply respective header
semantics when creating or receiving a request natural for the protocol in use.
<div class="example" heading="Making a use of a returned header">
<pre highlight="json-ld" line-highlight="11-16">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#comments",
"@type": "Link",
"supportedOperation": [
{
"@type": "Operation",
"method": "POST",
"expects": "http://api.example.com/doc/#Comment",
"returns": "http://api.example.com/doc/#Comment",
"returnsHeader": [
"Content-Type",
"Content-Length"],
"expectsHeader": [
"Authorization"
]
}
]
}
</pre>
</div>
The example above enable an HTTP client to prepare a proper cross-site
pre-flight request, so the server exposes enlisted headers for the client.
The client is also aware of the user authentication requirement necessary
for the operation invocation.
For more complex scenarios it is also possible to expand selected header
specification with both name and possible values, i.e. when defining
expected *Content-Type* values of resources that can be uploaded.
In case multiple possible values are provided, client SHOULD assume
that the set includes any of the values, but not limited to those values.
In order to change that default behavior it is possible to use [=closedSet=]
predicate on the header specification indicating that the set of provided
values is, well, closed and no other values are available. In both cases
the client SHOULD interpret a received payload at runtime for possible
discrepancies.
<div class="example" heading="Making a use of a expected header values">
<pre highlight="json-ld" line-highlight="11-24">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#comments",
"@type": "Link",
"supportedOperation": [
{
"@type": "Operation",
"method": "POST",
"expects": "http://api.example.com/doc/#Upload",
"returns": "http://api.example.com/doc/#Comment",
"returnsHeader": [
{
"headerName": "Content-Type",
"possibleValue": ["text/turtle", "application/ld+json"]
}
"Content-Length"
],
"expectsHeader": [
"Authorization",
{
"headerName": "Content-Type",
"possibleValue": ["image/gif", "image/png"]
}
]
}
]
}
</pre>
</div>
To wrap up everything altogether, it is also possible to attach atomic
operations supported by, well, supported property itself. This might
come in handy for scenarios, when resource can be partially modified.
It can be achieved with two approaches, both having advantages and
disadvantages.
First approach would involve adding a [=supportedOperation=] to the
intermediate structure of [=SupportedProperty=].
This way prevents from leaking API specific features from the API itself
to i.e. externally defined properties. Data aggregators won't assume that
each instance with a given property could have such an operation.
Another approach would require the API to elevate a specific property
to [=Link=], which can accept a [=supportedOperation=]. This
is more intuitive in APIs operating with internally used vocabularies
where assumption that every instance with that very specific property
has the operation attached available.
Direct usage of [=supportedOperation=] on *rdf:Property*
without elevating it to the [=Link=] SHOULD NOT be implemented as clients
may not discover such a construct correctly.
There are rare situations when some supported operations once announced in the
API documentation should be retracted, i.e. to reflect current state of the
application or current user capabilities (or lack of them). It is doable
with the [=retractedOperation=] predicate that can be added to the reasorce
the same way as the [=operation=] is. By default all operations are available
without limits and it is up for the server to change that, and for the client
to discover any discrepancies compared against the API documentation in the runtime.
Yet server may want to inform the client that at the very moment an operation is either
[=Unavailable=] or [=Unauthorized=] with a [=reason=] predicate.
The latter MAY be used to notify client that the user used to invoke
the request that provides operation availability information is currently
not authorized for that very operation to be invoked. The former on the other hand
MAY be used to inform that the operation is currently forbidden and client
SHOULD NOT invoke it. Server MAY also provide more custom reasons for which
the operation is not available but it SHOULD provide at least one of the
_Hydra_ built in reasons.
The [=retractedOperation=] MUST NOT be used in context of the [=ApiDocumentation=].
The [=retractedOperation=] predicate also MUST take precedence over both
[=operation=] and [=supportedOperation=] declaration and overrides them.
The operation that comes with [=retractedOperation=] predicate SHOULD be identified
using any of the below enlisted methods:
- Iri by using [=object=] predicate
- exact match of a resource described by [=possibleStatus=], [=method=], [=expects=], [=returns=] or combination of those
<div class="example" heading="Retracting operations - declaration of supported operations">
<pre highlight="json-ld">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/#comments",
"@type": "Link",
"supportedOperation": [
{
"@type": "Operation",
"method": "POST",
"expects": "http://api.example.com/doc/#Upload"
},
{
"@type": "Operation",
"method": "POST",
"expects": "http://api.example.com/doc/#Comment"
}
]
}
</pre>
</div>
<div class="example" heading="Retracting operations - matching">
<pre highlight="json-ld">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/",
"@type": "Collection",
"retractedOperation": [
{
"@type": "Operation",
"method": "POST",
"expects": "http://api.example.com/doc/#Upload",
"reason": "Unavailable"
}
]
}
</pre>
</div>
In the example above the operation that expects an uploaded file became
[=Unavailable=], while the one expecting a comment remains available as
the [=expects=] predicate does not match any supported operations.
It is still recommended to mark operations being subject for further
restrictions with an Iri as from the client perspective this may be
easier to implement simple literal Iri comparison rather than to compare
graphs of objects.
Note: These are the simple example scenarios and possible usages are not
limited to those described above.
Due to the fact an [=ApiDocumentation=] as all other resources may fail
at runtime, it is important to take countermeasures. A simple strategy
to try to recover from such a situation would be to reload
the [=ApiDocumentation=] and redo all pre-computations that were
based on the [=ApiDocumentation=] (or at least those that lead
to the current failure). Another, simpler approach would require
an application to show an error message with option to return
to a previous or home screen.
Hydra also allows enriching both [=ApiDocumentation=] and
hypermedia controls with human-readable descriptions by applying
[=title=] and [=description=] (as shown in the examples above).
The former states a name of such a decorated element that could
be displayed as a label. The latter provides its description
to be presented i.e. as a hint.
Aforementioned [=title=] and [=description=] SHOULD take precedence
over standard *rdfs:label* and *rdfs:comment*.
There is one more feature related to how Linked Data works. Consider the
example below written in turtle syntax:
<div class="example" heading="RDF as a graph">
<xmp highlight="turtle">
# An example API documentation itself with all the standard bits
@base <http://some.app/> .
@prefix api: <http://some.api/> .
@prefix ex: <http://ontology.example/> .
@prefix hydra: <http://www.w3.org/ns/hydra/core> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<api>
a hydra:ApiDocumentation ;
hydra:supportedClass api:ClassOne, api:ClassTwo .
# Anything else
ex:SomeType a rdfs:Class .
</xmp>
</div>
...and how it could be transformed with JSON-LD framing process:
<div class="example" heading="RDF as a graph continued">
<pre highlight="json-ld">
{
"@context": { ... },
"@graph": [
{
"@id": "http://some.app/api",
"@type": "hydra:ApiDocumentation",
"hydra:supportedClass": [
{
"@id": "api:ClassTwo"
},
{
"@id": "api:ClassOne"
}
]
}
]
}
</pre>
</div>
As you can see, additional details about *ex:SomeType* went
missing, while this shouldn't happen. The fact that the IRI mentioned
is an *rdfs:Class* may be meaningful for a correct interpretation
of the received payload and this is a sole reason of why a Client
SHOULD NOT disregard other parts of the payload that are not directly
related to the API documentation or other hypermedia controls.
## Discovering a Hydra-powered Web API ## {#discovering}
The first step when trying to access a Web API is to find an entry
point. Typically, this is done by looking for a documentation on the
API publisher's homepage. Hydra enables the API's main entry point
to be discovered automatically if the API publisher marks his
responses with a special HTTP Link Header as defined in [[!RFC8288]].
A Hydra client would look for a Link Header with a relation type
`http://www.w3.org/ns/hydra/core#apiDocumentation` (this is
the IRI identifying the [=apiDocumentation=] property).
In the following example, a Hydra client simply accesses the
homepage of an API publisher (`http://www.example.com/`)
to find the entry point of its API. A client may use an HTTP GET or
HEAD request. The difference between the two is that the former may
return a message-body in the response whereas the latter will not;
otherwise they are identical.
<div class="example" heading="Discovering Hydra API documentation documents">
<pre highlight="http" line-numbers>
HEAD / HTTP/1.1
Host: www.example.com
</pre>
<xmp highlight="http" line-highlight="4">
HTTP/1.1 200 OK
...
Content-Type: text/html; charset=utf-8
Link: <http://api.example.com/doc/>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
</xmp>
</div>
The response in the example above contains an HTTP Link Header
pointing to `http://api.example.com/doc/`. Retrieving that resource,
the client would obtain a [=ApiDocumentation|Hydra API documentation=]
defining the API's main entry point:
<div class="example" heading="Retrieving a Hydra API documentation to obtain the main entry point">
<pre highlight="http" line-numbers>
GET /doc/ HTTP/1.1
Host: api.example.com
Accept: application/ld+json
</pre>
<pre highlight="http" line-highlight="9">
HTTP/1.1 200 OK
...
Content-Type: application/ld+json
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/doc/",
"title": "The example.com API",
"entrypoint": "http://api.example.com/",
...
}
</pre>
</div>
Note: Please note that in some cases the entry point will already be
known to the client. Thus, the discovery of the API documentation
using HTTP Link Headers may not be necessary as the concepts
used in responses from the API will dereference to their documentation.
In another scenario the [=ApiDocumentation=] would be discovered from
a bookmarked resource's representation.
The [=ApiDocumentation|API implementation=] SHOULD emit the HTTP [=Link=]
header on every API response, making the [=ApiDocumentation=] (and entry
points it defined) discoverable all the time.
<div class="example" heading="Retrieving a Hydra API documentation from another API response">
<pre highlight="http" line-numbers>
GET /api/items HTTP/1.1
Host: api.example.com
Accept: application/ld+json
</pre>
<xmp highlight="http" line-highlight="4">
HTTP/1.1 200 OK
...
Content-Type: application/ld+json
Link: <http://api.example.com/doc/>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/api/items",
"title": "Items collection",
...
}
</xmp>
</div>
## Api versions ## {#api-versions}
It is common to provide a separate API address after a breaking changes
update. This prevents current clients not to get broken as these may not
support these changes.
With hypermedia provided in each response payload, it may be unnecessary
to provide such an alternative API. This is due to fact the client follows
what the server provides and with proper margin for errors implemented
within that client, even breaking changes can be published on the fly.
Still, Hydra does neither have any special support for API versions, nor
prevents them. It's fully an implementers decision on if and how
to provide the API features.
Advanced Concepts {#advanced-concepts}
=================
## Collections ## {#collections}
In many situations, it makes sense to expose resources that reference
a set of somehow related resources. Results of a search query or
entries of an address book are just two examples. To simplify such
use cases, Hydra defines the two classes [=Collection=] and
[=PartialCollectionView=].
A [=Collection=] can be used to reference a set of resources
as follows:
<div class="example" heading="Referencing related resources using a Hydra Collection">
<pre highlight="json-ld" line-highlight="4-6">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/an-issue/comments",
"@type": "Collection",
"totalItems": 4980,
"member" : [
{
"@id": "/comments/429"
},
{
"@id": "/comments/781",
"title": "Properties may be embedded directly in the collection"
},
...
]
}
</pre>
</div>
As shown in the example above, member items can either consist of
solely a link or also include some properties. In some cases embedding
member properties directly in the collection is beneficial as it may
reduce the number of HTTP requests necessary to get enough information
to process the result.
Since collections may become very large, Web APIs often chose to
split a collection into multiple pages. In Hydra, that can be achieved
with a [=PartialCollectionView=]. It describes a specific
view on the collection which represents only a subset of the collection's
members. A [=PartialCollectionView=] may contain links to the
[=first=], [=next=], [=previous=], and [=last=]
[=PartialCollectionView=] which allows a client to find all members
of a [=Collection=].
<div class="example" heading="A Hydra PartialCollectionView splits a collection into multiple views">
<pre highlight="json-ld" line-highlight="9,11-16">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/an-issue/comments",
"@type": "Collection",
"totalItems": 4980,
"member": [
// "... a subset of the members of the Collection ..."
],
"view": {
"@id": "http://api.example.com/an-issue/comments?page=3",
"@type": "PartialCollectionView",
"first": "/an-issue/comments?page=1",
"previous": "/an-issue/comments?page=2",
"next": "/an-issue/comments?page=4",
"last": "/an-issue/comments?page=498"
}
}
</pre>
</div>
Note: It is worth to mention that all those links are optional,
and it is up to server whether to provide these links or not.
## Member assertions ## {#member-assertions}
A [=memberAssertion=] (formerly `manages`) is a way to declare additional,
implicit statements about members of a [[#collections|collection]].
Statements which may otherwise be missing from the respective member
resources inlined in a collection's representation.
<div class="example" heading="Member assertion describes relation with another resource">
<pre highlight="json-ld" line-highlight="5-8">
{
"@context": "http://www.w3.org/ns/hydra/context.jsonld",
"@id": "http://api.example.com/an-issue/comments",
"@type": "Collection",
"memberAssertion": {
"subject": "http://api.example.com/an-issue",
"property": "http://api.example.com/vocab#comment"
},
"member": [
{
"@id": "/comments/429"
}
]
}
</pre>
</div>