forked from Logius-standaarden/API-Design-Rules
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnapshot.html
884 lines (818 loc) · 62.9 KB
/
snapshot.html
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
<!DOCTYPE html><html lang="en"><head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<meta name="generator" content="ReSpec 28.1.0 Logius profile 20220106">
<style>
.issue-label{text-transform:initial}
.warning>p:first-child{margin-top:0}
.warning{padding:.5em;border-left-width:.5em;border-left-style:solid}
span.warning{padding:.1em .5em .15em}
.issue.closed span.issue-number{text-decoration:line-through}
.warning{border-color:#f11;border-width:.2em;border-style:solid;background:#fbe9e9}
.warning-title:before{content:"⚠";font-size:1.3em;float:left;padding-right:.3em;margin-top:-.3em}
li.task-list-item{list-style:none}
input.task-list-item-checkbox{margin:0 .35em .25em -1.6em;vertical-align:middle}
.issue a.respec-gh-label{padding:5px;margin:0 2px 0 2px;font-size:10px;text-transform:none;text-decoration:none;font-weight:700;border-radius:4px;position:relative;bottom:2px;border:none;display:inline-block}
</style>
<style>
dfn{cursor:pointer}
.dfn-panel{position:absolute;z-index:35;min-width:300px;max-width:500px;padding:.5em .75em;margin-top:.6em;font:small Helvetica Neue,sans-serif,Droid Sans Fallback;background:#fff;color:#000;box-shadow:0 1em 3em -.4em rgba(0,0,0,.3),0 0 1px 1px rgba(0,0,0,.05);border-radius:2px}
.dfn-panel:not(.docked)>.caret{position:absolute;top:-9px}
.dfn-panel:not(.docked)>.caret::after,.dfn-panel:not(.docked)>.caret::before{content:"";position:absolute;border:10px solid transparent;border-top:0;border-bottom:10px solid #fff;top:0}
.dfn-panel:not(.docked)>.caret::before{border-bottom:9px solid #a2a9b1}
.dfn-panel *{margin:0}
.dfn-panel b{display:block;color:#000;margin-top:.25em}
.dfn-panel ul a[href]{color:#333}
.dfn-panel>div{display:flex}
.dfn-panel a.self-link{font-weight:700;margin-right:auto}
.dfn-panel .marker{padding:.1em;margin-left:.5em;border-radius:.2em;text-align:center;white-space:nowrap;font-size:90%;color:#040b1c}
.dfn-panel .marker.dfn-exported{background:#d1edfd;box-shadow:0 0 0 .125em #1ca5f940}
.dfn-panel .marker.idl-block{background:#8ccbf2;box-shadow:0 0 0 .125em #0670b161}
.dfn-panel a:not(:hover){text-decoration:none!important;border-bottom:none!important}
.dfn-panel a[href]:hover{border-bottom-width:1px}
.dfn-panel ul{padding:0}
.dfn-panel li{margin-left:1em}
.dfn-panel.docked{position:fixed;left:.5em;top:unset;bottom:2em;margin:0 auto;max-width:calc(100vw - .75em * 2 - .5em - .2em * 2);max-height:30vh;overflow:auto}
</style>
<title>API Design Rules (Nederlandse API Strategie IIa) 1.0</title>
<link rel="stylesheet" type="text/css" href="./media/style.css">
<link rel="shortcut icon" type="image/x-icon" href="https://publicatie.centrumvoorstandaarden.nl/respec/style/logos/logius.ico">
<style id="respec-mainstyle">
@keyframes pop{
0%{transform:scale(1,1)}
25%{transform:scale(1.25,1.25);opacity:.75}
100%{transform:scale(1,1)}
}
:is(h1,h2,h3,h4,h5,h6,a) abbr{border:none}
dfn{font-weight:700}
a.internalDFN{color:inherit;border-bottom:1px solid #99c;text-decoration:none}
a.externalDFN{color:inherit;border-bottom:1px dotted #ccc;text-decoration:none}
a.bibref{text-decoration:none}
.respec-offending-element:target{animation:pop .25s ease-in-out 0s 1}
.respec-offending-element,a[href].respec-offending-element{text-decoration:red wavy underline}
@supports not (text-decoration:red wavy underline){
.respec-offending-element:not(pre){display:inline-block}
.respec-offending-element{background:url(data:image/gif;base64,R0lGODdhBAADAPEAANv///8AAP///wAAACwAAAAABAADAEACBZQjmIAFADs=) bottom repeat-x}
}
#references :target{background:#eaf3ff;animation:pop .4s ease-in-out 0s 1}
cite .bibref{font-style:normal}
code{color:#c63501}
th code{color:inherit}
a[href].orcid{padding-left:4px;padding-right:4px}
a[href].orcid>svg{margin-bottom:-2px}
.toc a,.tof a{text-decoration:none}
a .figno,a .secno{color:#000}
ol.tof,ul.tof{list-style:none outside none}
.caption{margin-top:.5em;font-style:italic}
table.simple{border-spacing:0;border-collapse:collapse;border-bottom:3px solid #005a9c}
.simple th{background:#005a9c;color:#fff;padding:3px 5px;text-align:left}
.simple th a{color:#fff;padding:3px 5px;text-align:left}
.simple th[scope=row]{background:inherit;color:inherit;border-top:1px solid #ddd}
.simple td{padding:3px 10px;border-top:1px solid #ddd}
.simple tr:nth-child(even){background:#f0f6ff}
.section dd>p:first-child{margin-top:0}
.section dd>p:last-child{margin-bottom:0}
.section dd{margin-bottom:1em}
.section dl.attrs dd,.section dl.eldef dd{margin-bottom:0}
#issue-summary>ul{column-count:2}
#issue-summary li{list-style:none;display:inline-block}
details.respec-tests-details{margin-left:1em;display:inline-block;vertical-align:top}
details.respec-tests-details>*{padding-right:2em}
details.respec-tests-details[open]{z-index:999999;position:absolute;border:thin solid #cad3e2;border-radius:.3em;background-color:#fff;padding-bottom:.5em}
details.respec-tests-details[open]>summary{border-bottom:thin solid #cad3e2;padding-left:1em;margin-bottom:1em;line-height:2em}
details.respec-tests-details>ul{width:100%;margin-top:-.3em}
details.respec-tests-details>li{padding-left:1em}
a[href].self-link:hover{opacity:1;text-decoration:none;background-color:transparent}
h2,h3,h4,h5,h6{position:relative}
aside.example .marker>a.self-link{color:inherit}
:is(h2,h3,h4,h5,h6)>a.self-link{border:none;color:inherit;font-size:83%;height:2em;left:-1.6em;opacity:.5;position:absolute;text-align:center;text-decoration:none;top:0;transition:opacity .2s;width:2em}
:is(h2,h3,h4,h5,h6)>a.self-link::before{content:"§";display:block}
@media (max-width:767px){
dd{margin-left:0}
:is(h2,h3,h4,h5,h6)>a.self-link{left:auto;top:auto}
}
@media print{
.removeOnSave{display:none}
}
</style>
<meta name="description" content="This document contains a normative standard for designing APIs in the Dutch Public Sector.
The Governance of this standard is described in a separate repository and published by Logius.">
<style>
.hljs{display:block;overflow-x:auto;padding:.5em;color:#383a42;background:#fafafa}
.hljs-comment,.hljs-quote{color:#717277;font-style:italic}
.hljs-doctag,.hljs-formula,.hljs-keyword{color:#a626a4}
.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#ca4706;font-weight:700}
.hljs-literal{color:#0b76c5}
.hljs-addition,.hljs-attribute,.hljs-meta-string,.hljs-regexp,.hljs-string{color:#42803c}
.hljs-built_in,.hljs-class .hljs-title{color:#9a6a01}
.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#986801}
.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#336ae3}
.hljs-emphasis{font-style:italic}
.hljs-strong{font-weight:700}
.hljs-link{text-decoration:underline}
</style>
<style>
var{position:relative;cursor:pointer}
var[data-type]::after,var[data-type]::before{position:absolute;left:50%;top:-6px;opacity:0;transition:opacity .4s;pointer-events:none}
var[data-type]::before{content:"";transform:translateX(-50%);border-width:4px 6px 0 6px;border-style:solid;border-color:transparent;border-top-color:#000}
var[data-type]::after{content:attr(data-type);transform:translateX(-50%) translateY(-100%);background:#000;text-align:center;font-family:"Dank Mono","Fira Code",monospace;font-style:normal;padding:6px;border-radius:3px;color:#daca88;text-indent:0;font-weight:400}
var[data-type]:hover::after,var[data-type]:hover::before{opacity:1}
</style>
<script id="initialUserConfig" type="application/json">{
"specStatus": "DEF",
"specType": "ST",
"pubDomain": "api",
"shortName": "adr",
"publishDate": "2020-07-09",
"publishVersion": "1.0",
"editors": [
{
"name": "Frank Terpstra",
"company": "Geonovum",
"companyURL": "https://www.geonovum.nl"
},
{
"name": "Jan van Gelder",
"company": "Geonovum",
"companyURL": "https://www.geonovum.nl"
}
],
"authors": [
{
"name": "Jasper Roes",
"company": "Het Kadaster",
"companyURL": "https://www.kadaster.nl"
},
{
"name": "Joost Farla",
"company": "Het Kadaster",
"companyURL": "https://www.kadaster.nl"
}
],
"github": "https://github.com/Logius-standaarden/API-Design-Rules",
"nl_github": {
"issueBase": "https://github.com/Geonovum/KP-APIs/issues/",
"revision": "https://github.com/Logius-standaarden/API-Design-Rules/commits/",
"pullsBase": "https://github.com/Geonovum/KP-APIs/pulls"
},
"addSectionLinks": true,
"nl_addReleaseTagTitle": true,
"nl_organisationName": "Logius",
"nl_organisationPrefix": "LS-",
"nl_markdownEmbedImageInFigure": true,
"nl_organisationStylesURL": "https://publicatie.centrumvoorstandaarden.nl/respec/style/",
"nl_organisationPublishURL": "https://publicatie.centrumvoorstandaarden.nl/",
"nl_logo": {
"src": "https://publicatie.centrumvoorstandaarden.nl/respec/style/logos/figure-logius.svg",
"alt": "Logius",
"id": "Logius",
"height": 77,
"width": 44,
"url": "https://www.logius.nl/standaarden"
},
"alternateFormats": [
{
"label": "pdf",
"uri": "API-Design-Rules.pdf"
}
],
"localBiblio": {
"SemVer": {
"href": "https://semver.org",
"title": "Semantic Versioning 2.0.0",
"authors": [
"T. Preston-Werner"
],
"date": "June 2013",
"id": "semver"
}
},
"publishISODate": "2020-07-09T00:00:00.000Z",
"generatedSubtitle": "Definitive version 09 juli 2020"
}</script>
<link rel="stylesheet" href="https://publicatie.centrumvoorstandaarden.nl/respec/style/LS-DEF.css"></head>
<body class="h-entry informative toc-inline"><div class="head">
<a class="logo" href="https://www.logius.nl/standaarden"><img alt="Logius" height="77" id="Logius" src="https://publicatie.centrumvoorstandaarden.nl/respec/style/logos/figure-logius.svg" width="44">
</a> <h1 id="title" class="title">API Design Rules (Nederlandse API Strategie IIa) 1.0</h1>
<h2>
Logius Standard<br>
Definitive version
<time class="dt-published" datetime="2020-07-09">09 juli 2020</time>
</h2>
<a lang="nl" href="https://publicatie.centrumvoorstandaarden.nl/">Overzicht standaarden</a>
<dl>
<dt>This version:</dt><dd class="status">
<a class="u-url status" href="https://publicatie.centrumvoorstandaarden.nl/api/adr/1.0">https://publicatie.centrumvoorstandaarden.nl/api/adr/1.0</a>
</dd><dt>Latest published version:</dt><dd>
<a href="https://publicatie.centrumvoorstandaarden.nl/api/adr/">https://publicatie.centrumvoorstandaarden.nl/api/adr/</a>
</dd>
<dt>Latest editor's draft:</dt><dd><a href="https://logius-standaarden.github.io/API-Design-Rules/">https://logius-standaarden.github.io/API-Design-Rules/</a></dd>
<dt>Editors:</dt>
<dd class="editor p-author h-card vcard">
<span class="p-name fn">Frank Terpstra</span> (<a class="p-org org h-org" href="https://www.geonovum.nl">Geonovum</a>)
</dd><dd class="editor p-author h-card vcard">
<span class="p-name fn">Jan van Gelder</span> (<a class="p-org org h-org" href="https://www.geonovum.nl">Geonovum</a>)
</dd>
<dt>Authors:</dt><dd class="editor p-author h-card vcard">
<span class="p-name fn">Jasper Roes</span> (<a class="p-org org h-org" href="https://www.kadaster.nl">Het Kadaster</a>)
</dd><dd class="editor p-author h-card vcard">
<span class="p-name fn">Joost Farla</span> (<a class="p-org org h-org" href="https://www.kadaster.nl">Het Kadaster</a>)
</dd>
<dt>Participate:</dt><dd>
<a href="https://github.com/Logius-standaarden/API-Design-Rules/">GitHub Logius-standaarden/API-Design-Rules</a>
</dd><dd>
<a href="https://github.com/Geonovum/KP-APIs/issues/">File an issue</a>
</dd><dd>
<a href="https://github.com/Logius-standaarden/API-Design-Rules/commits/">Commit history</a>
</dd><dd>
<a href="https://github.com/Logius-standaarden/API-Design-Rules/pulls/">Pull requests</a>
</dd>
</dl>
<p lang="en">
This document is also available in this non-normative format:
<a rel="alternate" href="API-Design-Rules.pdf">pdf</a>
</p>
<p class="copyright" lang="en">
This document is licensed under a
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/" class="subfoot">Creative Commons Attribution 4.0 License</a>.
</p>
<hr title="Separator for header">
</div>
<section id="abstract" data-format="markdown" class="introductory"><h2 id="abstract-0">Abstract<a class="self-link" href="#abstract" aria-label="Permalink for Section"></a></h2><p>This document contains a normative standard for designing APIs in the Dutch Public Sector.
<a href="https://publicatie.centrumvoorstandaarden.nl/api/adr-beheer/">The Governance of this standard</a> is described in a <a href="https://github.com/Logius-standaarden/ADR-Beheermodel">separate repository</a> and published by Logius.</p></section>
<section id="sotd" class="introductory"><h2 id="status-of-this-document">Status of This Document<a class="self-link" href="#sotd" aria-label="Permalink for Section"></a></h2>This is the definitive version of the standard. Edits resulting from consultations have been applied.<p>Het OBDO heeft op advies van het Forum Standaardisatie deze versie vastgesteld.</p></section><nav id="toc"><h2 class="introductory" id="table-of-contents">Table of Contents</h2><ol class="toc"><li class="tocline"><a class="tocxref" href="#abstract">Abstract</a></li><li class="tocline"><a class="tocxref" href="#sotd">Status of This Document</a></li><li class="tocline"><a class="tocxref" href="#introduction"><bdi class="secno">1. </bdi>Introduction</a><ol class="toc"><li class="tocline"><a class="tocxref" href="#goal"><bdi class="secno">1.1 </bdi>Goal</a></li><li class="tocline"><a class="tocxref" href="#status"><bdi class="secno">1.2 </bdi>Status</a></li><li class="tocline"><a class="tocxref" href="#authors"><bdi class="secno">1.3 </bdi>Authors</a></li><li class="tocline"><a class="tocxref" href="#reading-guide"><bdi class="secno">1.4 </bdi>Reading Guide</a></li><li class="tocline"><a class="tocxref" href="#extensions"><bdi class="secno">1.5 </bdi>Extensions</a></li></ol></li><li class="tocline"><a class="tocxref" href="#summary"><bdi class="secno">2. </bdi>Summary</a><ol class="toc"><li class="tocline"><a class="tocxref" href="#normative-design-rules"><bdi class="secno">2.1 </bdi>Normative Design Rules</a></li></ol></li><li class="tocline"><a class="tocxref" href="#the-design-rules"><bdi class="secno">3. </bdi>The Design Rules</a><ol class="toc"><li class="tocline"><a class="tocxref" href="#resources"><bdi class="secno">3.1 </bdi>Resources</a></li><li class="tocline"><a class="tocxref" href="#http-methods"><bdi class="secno">3.2 </bdi>HTTP methods</a></li><li class="tocline"><a class="tocxref" href="#statelessness"><bdi class="secno">3.3 </bdi>Statelessness</a></li><li class="tocline"><a class="tocxref" href="#relationships"><bdi class="secno">3.4 </bdi>Relationships</a></li><li class="tocline"><a class="tocxref" href="#operations"><bdi class="secno">3.5 </bdi>Operations</a></li><li class="tocline"><a class="tocxref" href="#documentation"><bdi class="secno">3.6 </bdi>Documentation</a></li><li class="tocline"><a class="tocxref" href="#versioning"><bdi class="secno">3.7 </bdi>Versioning</a></li></ol></li><li class="tocline"><a class="tocxref" href="#glossary"><bdi class="secno">4. </bdi>Glossary</a></li><li class="tocline"><a class="tocxref" href="#references"><bdi class="secno">A. </bdi>References</a><ol class="toc"><li class="tocline"><a class="tocxref" href="#informative-references"><bdi class="secno">A.1 </bdi>Informative references</a></li></ol></li></ol></nav>
<section data-format="markdown" class="informative" id="introduction"><h2 id="x1-introduction"><bdi class="secno">1. </bdi>Introduction<a class="self-link" href="#introduction" aria-label="Permalink for Section 1."></a></h2><p><em>This section is non-normative.</em></p><section id="goal"><h3 id="x1-1-goal"><bdi class="secno">1.1 </bdi>Goal<a class="self-link" href="#goal" aria-label="Permalink for Section 1.1"></a></h3><p>More and more governmental organizations offer REST APIs (henceforth abbreviated as APIs), in addition to existing interfaces like SOAP and WFS. These APIs aim to be developer-friendly and easy to implement. While this is a commendable aim, it does not shield a developer from a steep learning curve getting to know every new API, in particular when every individual API is designed using different patterns and conventions.</p><p>This document aims to describe a widely applicable set of design rules for the unambiguous provisioning of REST APIs. The primary goal is to offer guidance for organizations designing new APIs, with the purpose of increasing developer experience (DX) and interoperability between APIs. Hopefully, many organizations will adopt these design rules in their corporate API strategies and provide feedback about exceptions and additions to subsequently improve these design rules.</p></section><section id="status"><h3 id="x1-2-status"><bdi class="secno">1.2 </bdi>Status<a class="self-link" href="#status" aria-label="Permalink for Section 1.2"></a></h3><p>This version of the design rules has been submitted to Forum Standaardisatie for inclusion on the Comply or Explain list of mandatory standards in the Dutch Public Sector. This document originates from the document <a href="https://docs.geostandaarden.nl/api/vv-hr-API-Strategie-20190715/">API Strategie voor de Nederlandse Overheid</a>, which was recently split into separate sub-documents.</p></section><section id="authors"><h3 id="x1-3-authors"><bdi class="secno">1.3 </bdi>Authors<a class="self-link" href="#authors" aria-label="Permalink for Section 1.3"></a></h3><p>Despite the fact that two authors are mentioned in the list of authors, this document is the result of a collaborative effort by the members of the <em>API Design Rules Working Group</em>.</p></section><section id="reading-guide"><h3 id="x1-4-reading-guide"><bdi class="secno">1.4 </bdi>Reading Guide<a class="self-link" href="#reading-guide" aria-label="Permalink for Section 1.4"></a></h3><p>This document is part of the <em>Nederlandse API Strategie</em>.</p><p>The Nederlandse API Strategie consists of <a href="https://www.geonovum.nl/themas/kennisplatform-apis#APIStrategie">three distinct documents</a>.</p></section><section id="extensions"><h3 id="x1-5-extensions"><bdi class="secno">1.5 </bdi>Extensions<a class="self-link" href="#extensions" aria-label="Permalink for Section 1.5"></a></h3><p>In addition to this (normative) document, a separate document has been written providing a set of informative extensions. This extensions document exists in a <em>latest published version</em> (<em>Gepubliceerde versie</em> in Dutch) and a <em>latest editors draft</em> (<em>Werkversie</em> in Dutch). The <em>latest editor's draft</em>s is actively being worked on and can be found on GitHub. It contains the most recent changes.</p><p>The documents can be found here:</p><ul>
<li><a href="https://docs.geostandaarden.nl/api/API-Strategie-ext/">Extensions Gepubliceerde versie</a></li>
<li><a href="https://geonovum.github.io/KP-APIs/API-strategie-extensies/">Extensions Werkversie</a></li>
</ul></section></section>
<section data-format="markdown" id="summary"><h2 id="x2-summary"><bdi class="secno">2. </bdi>Summary<a class="self-link" href="#summary" aria-label="Permalink for Section 2."></a></h2><div class="note" role="note" id="issue-container-generatedID"><div role="heading" class="note-title marker" id="h-note" aria-level="3"><span>Note</span></div><aside class="">
Design rules have unique and permanent numbers. In the event of design rules being deprecated or restructured, they are removed from the list. Therefore, gaps in the sequence can occur. New design rules will always get a new and higher number.
</aside></div><section id="normative-design-rules"><h3 id="x2-1-normative-design-rules"><bdi class="secno">2.1 </bdi>Normative Design Rules<a class="self-link" href="#normative-design-rules" aria-label="Permalink for Section 2.1"></a></h3><ul>
<li><a href="#api-01">API-01</a>: Adhere to HTTP safety and idempotency semantics for operations</li>
<li><a href="#api-02">API-02</a>: Do not maintain session state on the server</li>
<li><a href="#api-03">API-03</a>: Only apply standard HTTP methods</li>
<li><a href="#api-04">API-04</a>: Define interfaces in Dutch unless there is an official English glossary available</li>
<li><a href="#api-05">API-05</a>: Use nouns to name resources</li>
<li><a href="#api-06">API-06</a>: Use nested URIs for child resources</li>
<li><a href="#api-10">API-10</a>: Model resource operations as a sub-resource or dedicated resource</li>
<li><a href="#api-16">API-16</a>: Use OpenAPI Specification for documentation</li>
<li><a href="#api-17">API-17</a>: Publish documentation in Dutch unless there is existing documentation in English</li>
<li><a href="#api-18">API-18</a>: Include a deprecation schedule when publishing API changes</li>
<li><a href="#api-19">API-19</a>: Schedule a fixed transition period for a new major API version</li>
<li><a href="#api-20">API-20</a>: Include the major version number in the URI</li>
<li><a href="#api-48">API-48</a>: Leave off trailing slashes from URIs</li>
<li><a href="#api-51">API-51</a>: Publish OAS document at a standard location in JSON-format</li>
<li><a href="#api-53">API-53</a>: Hide irrelevant implementation details</li>
<li><a href="#api-54">API-54</a>: Use plural nouns to name collection resources</li>
<li><a href="#api-55">API-55</a>: Publish a changelog for API changes between versions</li>
<li><a href="#api-56">API-56</a>: Adhere to the Semantic Versioning model when releasing API changes</li>
<li><a href="#api-57">API-57</a>: Return the full version number in a response header</li>
</ul></section></section>
<section data-format="markdown" id="the-design-rules"><h2 id="x3-the-design-rules"><bdi class="secno">3. </bdi>The Design Rules<a class="self-link" href="#the-design-rules" aria-label="Permalink for Section 3."></a></h2><section id="resources"><h3 id="x3-1-resources"><bdi class="secno">3.1 </bdi>Resources<a class="self-link" href="#resources" aria-label="Permalink for Section 3.1"></a></h3><p>The REST architectural style is centered around the concept of a <a href="#dfn-resource" id="ref-for-dfn-resource-1">resource</a>. A resource is the key abstraction of information, where every piece of information is named by assigning a globally unique <a href="#dfn-uri" id="ref-for-dfn-uri-1">URI</a> (Uniform Resource Identifier). Resources describe <em>things</em>, which can vary between physical objects (e.g. a building or a person) and more abstract concepts (e.g. a permit or an event).</p><div class="rule" id="api-05">
<p class="rulelab"><b>API-05</b>: Use nouns to name resources</p>
<p>Because resources describe things (and thus not actions), resources are referred to using nouns (instead of verbs) that are relevant from the perspective of the user of the API.</p>
<div class="example">
<p>A few correct examples of nouns as part of a URI:</p>
<ul>
<li>Gebouw</li>
<li>Vergunning</li>
</ul>
<p>This is different than RPC-style APIs, where verbs are often used to perform certain actions:</p>
<ul>
<li>Opvragen</li>
<li>Registreren</li>
</ul>
</div>
</div><p>A resource describing a single thing is called a <a href="#dfn-singular-resource" id="ref-for-dfn-singular-resource-1">singular resource</a>. Resources can also be grouped into collections, which are resources in their own right and can typically be paged, sorted and filtered. Most often all collection members have the same type, but this is not necessarily the case. A resource describing multiple things is called a <a href="#dfn-collection-resource" id="ref-for-dfn-collection-resource-1">collection resource</a>. Collection resources typically contain references to the underlying singular resources.</p><div class="rule" id="api-54">
<p class="rulelab"><b>API-54</b>: Use plural nouns to name collection resources</p>
<p>Because a collection resource represents multiple things, the path segment describing the name of the collection resource must be written in the plural form.</p>
<div class="example">
<p>Example collection resources, describing a list of things:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/gebouwen</span>
https:<span class="hljs-comment">//api.example.org/v1/vergunningen</span></code></pre>
</div>
<p>Singular resources contained within a collection resource are generally named by appending a path segment for the identification of each individual resource.</p>
<div class="example">
<p>Example singular resource, contained within a collection resource:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/gebouwen/3b9710c4-6614-467a-ab82-36822cf48db1</span>
https:<span class="hljs-comment">//api.example.org/v1/vergunningen/d285e05c-6b01-45c3-92d8-5e19a946b66f</span></code></pre>
</div>
<p>Singular resources that stand on their own, i.e. which are not contained within a collection resource, must be named with a path segment that is written in the singular form.</p>
<div class="example">
<p>Example singular resource describing the profile of the currently authenticated user:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/gebruikersprofiel</span></code></pre>
</div>
</div><div class="rule" id="api-04">
<p class="rulelab"><b>API-04</b>: Define interfaces in Dutch unless there is an official English glossary available</p>
<p>Since the exact meaning of concepts is often lost in translation, resources and the underlying attributes should be defined in the Dutch language unless there is an official English glossary available. Publishing an API for an international audience might also be a reason to define interfaces in English.</p>
<p>Note that glossaries exist that define useful sets of attributes which should preferably be reused. Examples can be found at <a href="http://schema.org/docs/schemas.html">schema.org</a>.</p>
</div><div class="rule" id="api-48">
<p class="rulelab"><b>API-48</b>: Leave off trailing slashes from URIs</p>
<p>According to the URI specification [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc3986" title="Uniform Resource Identifier (URI): Generic Syntax">rfc3986</a></cite>], URIs may contain a trailing slash. However, for REST APIs this is considered as a bad practice since a URI including or excluding a trailing slash might be interpreted as different resources (which is strictly speaking the correct interpretation).</p>
<p>To avoid confusion and ambiguity, a URI must never contain a trailing slash. When requesting a resource including a trailing slash, this must result in a 404 (not found) error response and not a redirect. This enforces API consumers to use the correct URI.</p>
<div class="example">
<p>URI without a trailing slash (correct):</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/gebouwen</span></code></pre>
<p>URI with a trailing slash (incorrect):</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/gebouwen/</span></code></pre>
</div>
</div><div class="rule" id="api-53">
<p class="rulelab"><b>API-53</b>: Hide irrelevant implementation details</p>
<p>An API should not expose implementation details of the underlying application. The primary motivation behind this design rule is that an API design must focus on usability for the client, regardless of the implementation details under the hood. The API, application and infrastructure need to be able to evolve independently to ease the task of maintaining backwards compatibility for APIs during an agile development process.</p>
<p>A few examples of implementation details:</p>
<ul>
<li>The API design should not necessarily be a 1-on-1 mapping of the underlying domain- or persistence model</li>
<li>The API should not expose information about the technical components being used, such as development platforms/frameworks or database systems</li>
<li>The API should offer client-friendly attribute names and values, while persisted data may contain abbreviated terms or serializations which might be cumbersome for consumption</li>
</ul>
</div></section><section id="http-methods"><h3 id="x3-2-http-methods"><bdi class="secno">3.2 </bdi>HTTP methods<a class="self-link" href="#http-methods" aria-label="Permalink for Section 3.2"></a></h3><p>Although the REST architectural style does not impose a specific protocol, REST APIs are typically implemented using HTTP [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc7231" title="Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content">rfc7231</a></cite>].</p><div class="rule" id="api-03">
<p class="rulelab"><b>API-03</b>: Only apply standard HTTP methods</p>
<p>The HTTP specification [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc7231" title="Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content">rfc7231</a></cite>] and the later introduced <code>PATCH</code> method specification [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc5789" title="PATCH Method for HTTP">rfc5789</a></cite>] offer a set of standard methods, where every method is designed with explicit semantics. Adhering to the HTTP specification is crucial, since HTTP clients and middleware applications rely on standardized characteristics. Therefore, resources must be retrieved or manipulated using standard HTTP methods.</p>
<table class="simple">
<thead>
<tr>
<th scope="col">Method</th>
<th scope="col">Operation</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>GET</code></td>
<td>Read</td>
<td>Retrieve a resource representation for the given URI. Data is only retrieved and never modified.</td>
</tr>
<tr>
<td><code>POST</code></td>
<td>Create</td>
<td>Create a subresource as part of a collection resource. This operation is not relevant for singular resources. This method can also be used for <a href="#api-10">exceptional cases</a>.</td>
</tr>
<tr>
<td><code>PUT</code></td>
<td>Create/update</td>
<td>Create a resource with the given URI or replace (full update) a resource when the resource already exists.</td>
</tr>
<tr>
<td><code>PATCH</code></td>
<td>Update</td>
<td>Partially updates an existing resource. The request only contains the resource modifications instead of the full resource representation.</td>
</tr>
<tr>
<td><code>DELETE</code></td>
<td>Delete</td>
<td>Remove a resource with the given URI.</td>
</tr>
</tbody>
</table>
<p>The following table shows some examples of the use of standard HTTP methods:</p>
<table class="simple">
<thead>
<tr>
<th scope="col">Request</th>
<th scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>GET /rijksmonumenten</code></td>
<td>Retrieves a list of national monuments.</td>
</tr>
<tr>
<td><code>GET /rijksmonumenten/12</code></td>
<td>Retrieves an individual national monument.</td>
</tr>
<tr>
<td><code>POST /rijksmonumenten</code></td>
<td>Creates a new national monument.</td>
</tr>
<tr>
<td><code>PUT /rijksmonumenten/12</code></td>
<td>Modifies national monument #12 completely.</td>
</tr>
<tr>
<td><code>PATCH /rijksmonumenten/12</code></td>
<td>Modifies national monument #12 partially.</td>
</tr>
<tr>
<td><code>DELETE /rijksmonumenten/12</code></td>
<td>Deletes national monument #12.</td>
</tr>
</tbody>
</table>
<p class="note">HTTP also defines other methods, e.g. <code>HEAD</code>, <code>OPTIONS</code> and <code>TRACE</code>. For the purpose of this design rule, these operations are left out of scope.</p>
</div><div class="rule" id="api-01">
<p class="rulelab"><b>API-01</b>: Adhere to HTTP safety and idempotency semantics for operations</p>
<p>The HTTP protocol [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc7231" title="Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content">rfc7231</a></cite>] specifies whether an HTTP method should be considered safe and/or idempotent. These characteristics are important for clients and middleware applications, because they should be taken into account when implementing caching and fault tolerance strategies.</p>
<p>Request methods are considered <i>safe</i> if their defined semantics are essentially read-only; i.e., the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource. A request method is considered <i>idempotent</i> if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.</p>
<p>The following table describes which HTTP methods must behave as safe and/or idempotent:</p>
<table class="simple">
<thead>
<tr>
<th scope="col">Method</th>
<th scope="col">Safe</th>
<th scope="col">Idempotent</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>GET</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>HEAD</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>OPTIONS</code></td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td><code>POST</code></td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td><code>PUT</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>PATCH</code></td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td><code>DELETE</code></td>
<td>No</td>
<td>Yes</td>
</tr>
</tbody>
</table>
</div></section><section id="statelessness"><h3 id="x3-3-statelessness"><bdi class="secno">3.3 </bdi>Statelessness<a class="self-link" href="#statelessness" aria-label="Permalink for Section 3.3"></a></h3><p>One of the key constraints of the REST architectural style is stateless communication between client and server. It means that every request from client to server must contain all of the information necessary to understand the request. The server cannot take advantage of any stored session context on the server as it didn’t memorize previous requests. Session state must therefore reside entirely on the client.</p><p>To properly understand this constraint, it's important to make a distinction between two different kinds of state:</p><ul>
<li><em>Session state</em>: information about the interactions of an end user with a particular client application within the same user session, such as the last page being viewed, the login state or form data in a multi-step registration process. Session state must reside entirely on the client (e.g. in the user's browser).</li>
<li><em>Resource state</em>: information that is permanently stored on the server beyond the scope of a single user session, such as the user's profile, a product purchase or information about a building. Resource state is persisted on the server and must be exchanged between client and server (in both directions) using representations as part of the request or response payload. This is actually where the term <em>REpresentational State Transfer (REST)</em> originates from.</li>
</ul><p class="note">It's a misconception that there should be no state at all. The stateless communication constraint should be seen from the server's point of view and states that the server should not be aware of any <em>session state</em>.</p><p>Stateless communication offers many advantages, including:</p><ul>
<li><em>Simplicity</em> is increased because the server doesn't have to memorize or retrieve session state while processing requests</li>
<li><em>Scalability</em> is improved because not having to incorporate session state across multiple requests enables higher concurrency and performance</li>
<li><em>Observability</em> is improved since every request can be monitored or analyzed in isolation without having to incorporate session context from other requests</li>
<li><em>Reliability</em> is improved because it eases the task of recovering from partial failures since the server doesn't have to maintain, update or communicate session state. One failing request does not influence other requests (depending on the nature of the failure of course).</li>
</ul><div class="rule" id="api-02">
<p class="rulelab"><b>API-02</b>: Do not maintain session state on the server</p>
<p>In the context of REST APIs, the server must not maintain or require any notion of the functionality of the client application and the corresponding end user interactions. To achieve full decoupling between client and server, and to benefit from the advantages mentioned above, no session state must reside on the server. Session state must therefore reside entirely on the client.</p>
<p class="note">The client of a REST API could be a variety of applications such as a browser application, a mobile or desktop application and even another server serving as a backend component for another client. REST APIs should therefore be completely client-agnostic.</p>
</div></section><section id="relationships"><h3 id="x3-4-relationships"><bdi class="secno">3.4 </bdi>Relationships<a class="self-link" href="#relationships" aria-label="Permalink for Section 3.4"></a></h3><p>Resources are often interconnected by relationships. Relationships can be modelled in different ways depending on the cardinality, semantics and more importantly, the use cases and access patterns the REST API needs to support.</p><div class="rule" id="api-06">
<p class="rulelab"><b>API-06</b>: Use nested URIs for child resources</p>
<p>When having a child resource which can only exist in the context of a parent resource, the URI should be nested. In that case, the child resource does not necessarily have a top-level collection resource. The best way to explain this design rule is by example.</p>
<div class="example">
<p>When modelling resources for a news platform including the ability for users to write comments, it might be a good strategy to model the <a href="#dfn-collection-resource" id="ref-for-dfn-collection-resource-2">collection resources</a> hierarchically:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/articles/123/comments</span></code></pre>
<p>The platform might also offer a photo section, where the same commenting functionality is offered. In the same way as for articles, the corresponding sub-collection resource might be published at:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/photos/456/comments</span></code></pre>
<p>These nested sub-collection resources can be used to post a new comment (<code>POST</code> method) and to retrieve a list of comments (<code>GET</code> method) belonging to the parent resource, i.e. the article or photo. An important consideration is that these comments could never have existed without the existence of the parent resource.</p>
<p>From the consumer's perspective, this approach makes logical sense, because the most obvious use case is to show comments below the parent article or photo (e.g. on the same web page) including the possibility to paginate through the comments. The process of posting a comment is separate from the process of publishing a new article. Another client use case might also be to show a global <em>latest comments</em> section in the sidebar. For this use case, an additional resource could be provided:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/comments</span></code></pre>
<p>If this would have not been a meaningful use case, this resource should not exist at all. Because it doesn't make sense to post a new comment from a global context, this resource would be read-only (only <code>GET</code> method is supported) and may possibly provide a more compact representation than the parent-specific sub-collections.</p>
<p>The <a href="#dfn-singular-resource" id="ref-for-dfn-singular-resource-2">singular resources</a> for comments, referenced from all 3 collections, could still be modelled on a higher level to avoid deep nesting of URIs (which might increase complexity or problems due to the URI length):</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/comments/123</span>
https:<span class="hljs-comment">//api.example.org/v1/comments/456</span></code></pre>
<p>Although this approach might seem counterintuitive from a technical perspective (we simply could have modelled a single <code>/comments</code> resource with optional filters for article and photo) and might introduce partially redundant functionality, it makes perfect sense from the perspective of the consumer, which increases developer experience.</p>
</div>
</div></section><section id="operations"><h3 id="x3-5-operations"><bdi class="secno">3.5 </bdi>Operations<a class="self-link" href="#operations" aria-label="Permalink for Section 3.5"></a></h3><div class="rule" id="api-10">
<p class="rulelab"><b>API-10</b>: Model resource operations as a sub-resource or dedicated resource</p>
<p>There are resource operations which might not seem to fit well in the CRUD interaction model. For example, approving of a submission or notifying a customer. Depending on the type of the operation, there are three possible approaches:</p>
<ol>
<li>Re-model the resource to incorporate extra fields supporting the particular operation. For example, an approval operation can be modelled in a boolean attribute <code>goedgekeurd</code> that can be modified by issuing a <code>PATCH</code> request against the resource. Drawback of this approach is that the resource does not contain any metadata about the operation (when and by whom was the approval given? Was the submission declined in an earlier stage?). Furthermore, this requires a fine-grained authorization model, since approval might require a specific role.</li>
<li>Treat the operation as a sub-resource. For example, model a sub-collection resource <code>/inzendingen/12/beoordelingen</code> and add an approval or declination by issuing a <code>POST</code> request. To be able to retrieve the review history (and to consistently adhere to the REST principles), also support the <code>GET</code> method for this resource. The <code>/inzendingen/12</code> resource might still provide a <code>goedgekeurd</code> boolean attribute (same as approach 1) which gets automatically updated on the background after adding a review. This attribute should however be read-only.</li>
<li>In exceptional cases, the approaches above still don't offer an appropriate solution. An example of such an operation is a global search across multiple resources. In this case, the creation of a dedicated resource, possibly nested under an existing resource, is the most obvious solution. Use the imperative mood of a verb, maybe even prefix it with a underscore to distinguish these resources from regular resources. For example: <code>/search</code> or <code>/_search</code>. Depending on the operation characteristics, <code>GET</code> and/or <code>POST</code> method may be supported for such a resource.</li>
</ol>
<p>In this design rule, approach 2 and 3 are preferred.</p>
</div></section><section id="documentation"><h3 id="x3-6-documentation"><bdi class="secno">3.6 </bdi>Documentation<a class="self-link" href="#documentation" aria-label="Permalink for Section 3.6"></a></h3><p>An API is as good as the accompanying documentation. The documentation has to be easily findable, searchable and publicly accessible. Most developers will first read the documentation before they start implementing. Hiding the technical documentation in PDF documents and/or behind a login creates a barrier for both developers and search engines.</p><div class="rule" id="api-16">
<p class="rulelab"><b>API-16</b>: Use OpenAPI Specification for documentation</p>
<p>The OpenAPI Specification (OAS) [<cite><a class="bibref" data-link-type="biblio" href="#bib-openapis" title="OpenAPI Specification">OPENAPIS</a></cite>] defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.</p>
<p>API documentation must be provided in the form of an OpenAPI definition document which conforms to the OpenAPI Specification (from v3 onwards). As a result, a variety of tools can be used to render the documentation (e.g. Swagger UI or ReDoc) or automate tasks such as testing or code generation. The OAS document should provide clear descriptions and examples.</p>
</div><div class="rule" id="api-17">
<p class="rulelab"><b>API-17</b>: Publish documentation in Dutch unless there is existing documentation in English</p>
<p>In line with design rule <a href="#api-04">API-04</a>, the OAS document (e.g. descriptions and examples) should be written in Dutch. If relevant, you may refer to existing documentation written in English.</p>
</div><div class="rule" id="api-51">
<p class="rulelab"><b>API-51</b>: Publish OAS document at a standard location in JSON-format</p>
<p>To make the OAS document easy to find and to facilitate self-discovering clients, there should be one standard location where the OAS document is available for download. Clients (such as Swagger UI or ReDoc) must be able to retrieve the document without having to authenticate. Furthermore, the CORS policy for this URI must allow external domains to read the documentation from a browser environment.</p>
<p>The standard location for the OAS document is a URI called <code>openapi.json</code> or <code>openapi.yaml</code> within the base path of the API. This can be convenient, because OAS document updates can easily become part of the CI/CD process.</p>
<p>At least the JSON format must be supported. When having multiple (major) versions of an API, every API should provide its own OAS document(s).</p>
<div class="example">
<p>An API having base path <code>https://api.example.org/v1/</code> must publish the OAS document at:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/openapi.json</span></code></pre>
<p>Optionally, the same OAS document may be provided in YAML format:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/openapi.yaml</span></code></pre>
</div>
</div></section><section id="versioning"><h3 id="x3-7-versioning"><bdi class="secno">3.7 </bdi>Versioning<a class="self-link" href="#versioning" aria-label="Permalink for Section 3.7"></a></h3><p>Changes in APIs are inevitable. APIs should therefore always be versioned, facilitating the transition between changes.</p><div class="rule" id="api-56">
<p class="rulelab"><b>API-56</b>: Adhere to the Semantic Versioning model when releasing API changes</p>
<p>Version numbering must follow the Semantic Versioning [<cite><a class="bibref" data-link-type="biblio" href="#bib-semver" title="Semantic Versioning 2.0.0">SemVer</a></cite>] model to prevent breaking changes when releasing new API versions. Versions are formatted using the <code>major.minor.patch</code> template. When releasing a new version which contains backwards-incompatible changes, a new major version must be released. Minor and patch releases may only contain backwards compatible changes (e.g. the addition of an endpoint or an optional attribute).</p>
</div><div class="rule" id="api-20">
<p class="rulelab"><b>API-20</b>: Include the major version number in the URI</p>
<p>The URI of an API (base path) must include the major version number, prefixed by the letter <code>v</code>. This allows the exploration of multiple versions of an API in the browser. The minor and patch version numbers are not part of the URI and may not have any impact on existing client implementations.</p>
<div class="example">
<p>An example of a base path for an API with current version 1.0.2:</p>
<pre aria-busy="false"><code class="hljs javascript">https:<span class="hljs-comment">//api.example.org/v1/</span></code></pre>
</div>
</div><div class="rule" id="api-57">
<p class="rulelab"><b>API-57</b>: Return the full version number in a response header</p>
<p>Since the URI only contains the major version, it's useful to provide the full version number in the response headers for every API call. This information could then be used for logging, debugging or auditing purposes. In cases where an intermediate networking component returns an error response (e.g. a reverse proxy enforcing access policies), the version number may be omitted.</p>
<p>The version number must be returned in an HTTP response header named <code>API-Version</code> (case-insensitive) and should not be prefixed.</p>
<div class="example">
<p>An example of an API version response header:</p>
<pre aria-busy="false"><code class="hljs">API-Version: 1.0.2</code></pre>
</div>
</div><div class="rule" id="api-55">
<p class="rulelab"><b>API-55</b>: Publish a changelog for API changes between versions</p>
<p>When releasing new (major, minor or patch) versions, all API changes must be documented properly in a publicly available changelog.</p>
</div><div class="rule" id="api-18">
<p class="rulelab"><b>API-18</b>: Include a deprecation schedule when deprecating features or versions</p>
<p>Managing change is important. In general, well documented and timely communicated deprecation schedules are the most important for API users. When deprecating features or versions, a deprecation schedule must be published. This document should be published on a public web page. Furthermore, active clients should be informed by e-mail once the schedule has been updated or when versions have reached end-of-life.</p>
</div><div class="rule" id="api-19">
<p class="rulelab"><b>API-19</b>: Schedule a fixed transition period for a new major API version</p>
<p>When releasing a new major API version, the old version must remain available for a limited and fixed deprecation period. Offering a deprecation period allows clients to carefully plan and execute the migration from the old to the new API version, as long as they do this prior to the end of the deprecation period. A maximum of 2 major API versions may be published concurrently.</p>
</div></section></section>
<section data-format="markdown" id="glossary"><h2 id="x4-glossary"><bdi class="secno">4. </bdi>Glossary<a class="self-link" href="#glossary" aria-label="Permalink for Section 4."></a></h2><dl>
<dt>
<dfn id="dfn-resource" data-dfn-type="dfn" tabindex="0" aria-haspopup="dialog">Resource</dfn>
</dt>
<dd>
<p>A resource is the key abstraction of information, where every piece of information is identified by a globally unique <a href="#dfn-uri" id="ref-for-dfn-uri-2">URI</a>.</p>
</dd>
<dt>
<dfn id="dfn-singular-resource" data-dfn-type="dfn" tabindex="0" aria-haspopup="dialog">Singular resource</dfn>
</dt>
<dd>
<p>A singular resource is a resource describing a single thing (e.g. a building, person or event).</p>
</dd>
<dt>
<dfn id="dfn-collection-resource" data-dfn-type="dfn" tabindex="0" aria-haspopup="dialog">Collection resource</dfn>
</dt>
<dd>
<p>A collection resource is a resource describing multiple things (e.g. a list of buildings).</p>
</dd>
<dt>
<dfn id="dfn-uri" data-dfn-type="dfn" tabindex="0" aria-haspopup="dialog">URI</dfn>
</dt>
<dd>
<p>A URI [<cite><a class="bibref" data-link-type="biblio" href="#bib-rfc3986" title="Uniform Resource Identifier (URI): Generic Syntax">rfc3986</a></cite>] (Uniform Resource Identifier) is a globally unique identifier for a resource.</p>
</dd>
</dl></section>
<section id="references" class="appendix"><h2 id="a-references"><bdi class="secno">A. </bdi>References<a class="self-link" href="#references" aria-label="Permalink for Appendix A."></a></h2><section id="informative-references">
<h3 id="a-1-informative-references"><bdi class="secno">A.1 </bdi>Informative references<a class="self-link" href="#informative-references" aria-label="Permalink for Appendix A.1"></a></h3>
<dl class="bibliography"><dt id="bib-openapis">[OPENAPIS]</dt><dd><a href="https://www.openapis.org/"><cite>OpenAPI Specification</cite></a>. Darrell Miller; Jeremy Whitlock; Marsh Gardiner; Mike Ralphson; Ron Ratovsky; Uri Sarid; Tony Tam; Jason Harmon. OpenAPI Initiative. URL: <a href="https://www.openapis.org/">https://www.openapis.org/</a></dd><dt id="bib-rfc3986">[rfc3986]</dt><dd><a href="https://www.rfc-editor.org/rfc/rfc3986"><cite>Uniform Resource Identifier (URI): Generic Syntax</cite></a>. T. Berners-Lee; R. Fielding; L. Masinter. IETF. January 2005. Internet Standard. URL: <a href="https://www.rfc-editor.org/rfc/rfc3986">https://www.rfc-editor.org/rfc/rfc3986</a></dd><dt id="bib-rfc5789">[rfc5789]</dt><dd><a href="https://httpwg.org/specs/rfc5789.html"><cite>PATCH Method for HTTP</cite></a>. L. Dusseault; J. Snell. IETF. March 2010. Proposed Standard. URL: <a href="https://httpwg.org/specs/rfc5789.html">https://httpwg.org/specs/rfc5789.html</a></dd><dt id="bib-rfc7231">[rfc7231]</dt><dd><a href="https://httpwg.org/specs/rfc7231.html"><cite>Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</cite></a>. R. Fielding, Ed.; J. Reschke, Ed.. IETF. June 2014. Proposed Standard. URL: <a href="https://httpwg.org/specs/rfc7231.html">https://httpwg.org/specs/rfc7231.html</a></dd><dt id="bib-semver">[SemVer]</dt><dd><a href="https://semver.org"><cite>Semantic Versioning 2.0.0</cite></a>. T. Preston-Werner. June 2013. URL: <a href="https://semver.org">https://semver.org</a></dd></dl>
</section></section><p role="navigation" id="back-to-top">
<a href="#title"><abbr title="Back to Top">↑</abbr></a>
</p><div class="dfn-panel" hidden="" role="dialog" aria-modal="true" id="dfn-panel-for-dfn-resource" aria-label="Links in this document to definition: Resource">
<span class="caret"></span>
<div>
<a class="self-link" href="#dfn-resource" aria-label="Permalink for definition: Resource. Activate to close this dialog.">Permalink</a>
</div>
<p><b>Referenced in:</b></p>
<ul>
<li>
<a href="#ref-for-dfn-resource-1" title="§ 3.1 Resources">§ 3.1 Resources</a>
</li>
</ul>
</div><div class="dfn-panel" hidden="" role="dialog" aria-modal="true" id="dfn-panel-for-dfn-singular-resource" aria-label="Links in this document to definition: Singular resource">
<span class="caret"></span>
<div>
<a class="self-link" href="#dfn-singular-resource" aria-label="Permalink for definition: Singular resource. Activate to close this dialog.">Permalink</a>
</div>
<p><b>Referenced in:</b></p>
<ul>
<li>
<a href="#ref-for-dfn-singular-resource-1" title="§ 3.1 Resources">§ 3.1 Resources</a>
</li><li>
<a href="#ref-for-dfn-singular-resource-2" title="§ 3.4 Relationships">§ 3.4 Relationships</a>
</li>
</ul>
</div><div class="dfn-panel" hidden="" role="dialog" aria-modal="true" id="dfn-panel-for-dfn-collection-resource" aria-label="Links in this document to definition: Collection resource">
<span class="caret"></span>
<div>
<a class="self-link" href="#dfn-collection-resource" aria-label="Permalink for definition: Collection resource. Activate to close this dialog.">Permalink</a>
</div>
<p><b>Referenced in:</b></p>
<ul>
<li>
<a href="#ref-for-dfn-collection-resource-1" title="§ 3.1 Resources">§ 3.1 Resources</a>
</li><li>
<a href="#ref-for-dfn-collection-resource-2" title="§ 3.4 Relationships">§ 3.4 Relationships</a>
</li>
</ul>
</div><div class="dfn-panel" hidden="" role="dialog" aria-modal="true" id="dfn-panel-for-dfn-uri" aria-label="Links in this document to definition: URI">
<span class="caret"></span>
<div>
<a class="self-link" href="#dfn-uri" aria-label="Permalink for definition: URI. Activate to close this dialog.">Permalink</a>
</div>
<p><b>Referenced in:</b></p>
<ul>
<li>
<a href="#ref-for-dfn-uri-1" title="§ 3.1 Resources">§ 3.1 Resources</a>
</li><li>
<a href="#ref-for-dfn-uri-2" title="§ 4. Glossary">§ 4. Glossary</a>
</li>
</ul>
</div><script id="respec-dfn-panel">(() => {
// @ts-check
if (document.respec) {
document.respec.ready.then(setupPanel);
} else {
setupPanel();
}
function setupPanel() {
const listener = panelListener();
document.body.addEventListener("keydown", listener);
document.body.addEventListener("click", listener);
}
function panelListener() {
/** @type {HTMLElement} */
let panel = null;
return event => {
const { target, type } = event;
if (!(target instanceof HTMLElement)) return;
// For keys, we only care about Enter key to activate the panel
// otherwise it's activated via a click.
if (type === "keydown" && event.key !== "Enter") return;
const action = deriveAction(event);
switch (action) {
case "show": {
hidePanel(panel);
/** @type {HTMLElement} */
const dfn = target.closest("dfn, .index-term");
panel = document.getElementById(`dfn-panel-for-${dfn.id}`);
const coords = deriveCoordinates(event);
displayPanel(dfn, panel, coords);
break;
}
case "dock": {
panel.style.left = null;
panel.style.top = null;
panel.classList.add("docked");
break;
}
case "hide": {
hidePanel(panel);
panel = null;
break;
}
}
};
}
/**
* @param {MouseEvent|KeyboardEvent} event
*/
function deriveCoordinates(event) {
const target = /** @type HTMLElement */ (event.target);
// We prevent synthetic AT clicks from putting
// the dialog in a weird place. The AT events sometimes
// lack coordinates, so they have clientX/Y = 0
const rect = target.getBoundingClientRect();
if (
event instanceof MouseEvent &&
event.clientX >= rect.left &&
event.clientY >= rect.top
) {
// The event probably happened inside the bounding rect...
return { x: event.clientX, y: event.clientY };
}
// Offset to the middle of the element
const x = rect.x + rect.width / 2;
// Placed at the bottom of the element
const y = rect.y + rect.height;
return { x, y };
}
/**
* @param {Event} event
*/
function deriveAction(event) {
const target = /** @type {HTMLElement} */ (event.target);
const hitALink = !!target.closest("a");
if (target.closest("dfn:not([data-cite]), .index-term")) {
return hitALink ? "none" : "show";
}
if (target.closest(".dfn-panel")) {
if (hitALink) {
return target.classList.contains("self-link") ? "hide" : "dock";
}
const panel = target.closest(".dfn-panel");
return panel.classList.contains("docked") ? "hide" : "none";
}
if (document.querySelector(".dfn-panel:not([hidden])")) {
return "hide";
}
return "none";
}
/**
* @param {HTMLElement} dfn
* @param {HTMLElement} panel
* @param {{ x: number, y: number }} clickPosition
*/
function displayPanel(dfn, panel, { x, y }) {
panel.hidden = false;
// distance (px) between edge of panel and the pointing triangle (caret)
const MARGIN = 20;
const dfnRects = dfn.getClientRects();
// Find the `top` offset when the `dfn` can be spread across multiple lines
let closestTop = 0;
let minDiff = Infinity;
for (const rect of dfnRects) {
const { top, bottom } = rect;
const diffFromClickY = Math.abs((top + bottom) / 2 - y);
if (diffFromClickY < minDiff) {
minDiff = diffFromClickY;
closestTop = top;
}
}
const top = window.scrollY + closestTop + dfnRects[0].height;
const left = x - MARGIN;
panel.style.left = `${left}px`;
panel.style.top = `${top}px`;
// Find if the panel is flowing out of the window
const panelRect = panel.getBoundingClientRect();
const SCREEN_WIDTH = Math.min(window.innerWidth, window.screen.width);
if (panelRect.right > SCREEN_WIDTH) {
const newLeft = Math.max(MARGIN, x + MARGIN - panelRect.width);
const newCaretOffset = left - newLeft;
panel.style.left = `${newLeft}px`;
/** @type {HTMLElement} */
const caret = panel.querySelector(".caret");
caret.style.left = `${newCaretOffset}px`;
}
// As it's a dialog, we trap focus.
// TODO: when <dialog> becomes a implemented, we should really
// use that.
trapFocus(panel, dfn);
}
/**
* @param {HTMLElement} panel
* @param {HTMLElement} dfn
* @returns
*/
function trapFocus(panel, dfn) {
/** @type NodeListOf<HTMLAnchorElement> elements */
const anchors = panel.querySelectorAll("a[href]");
// No need to trap focus
if (!anchors.length) return;
// Move focus to first anchor element
const first = anchors.item(0);
first.focus();
const trapListener = createTrapListener(anchors, panel, dfn);
panel.addEventListener("keydown", trapListener);
// Hiding the panel releases the trap
const mo = new MutationObserver(records => {
const [record] = records;
const target = /** @type HTMLElement */ (record.target);
if (target.hidden) {
panel.removeEventListener("keydown", trapListener);
mo.disconnect();
}
});
mo.observe(panel, { attributes: true, attributeFilter: ["hidden"] });
}
/**
*
* @param {NodeListOf<HTMLAnchorElement>} anchors
* @param {HTMLElement} panel
* @param {HTMLElement} dfn
* @returns
*/
function createTrapListener(anchors, panel, dfn) {
const lastIndex = anchors.length - 1;
let currentIndex = 0;
return event => {
switch (event.key) {
// Hitting "Tab" traps us in a nice loop around elements.
case "Tab": {
event.preventDefault();
currentIndex += event.shiftKey ? -1 : +1;
if (currentIndex < 0) {
currentIndex = lastIndex;
} else if (currentIndex > lastIndex) {
currentIndex = 0;
}
anchors.item(currentIndex).focus();
break;
}
// Hitting "Enter" on an anchor releases the trap.
case "Enter":
hidePanel(panel);
break;
// Hitting "Escape" returns focus to dfn.
case "Escape":
hidePanel(panel);
dfn.focus();
return;
}
};
}
/** @param {HTMLElement} panel */
function hidePanel(panel) {
if (!panel) return;
panel.hidden = true;
panel.classList.remove("docked");
}
})()</script><script src="https://www.w3.org/scripts/TR/2021/fixup.js"></script></body></html>