Skip to content

Commit 6df6462

Browse files
committed
Discuss content negotiation. See #131.
1 parent 0582ce8 commit 6df6462

File tree

1 file changed

+299
-1
lines changed

1 file changed

+299
-1
lines changed

draft-ietf-httpapi-rest-api-mediatypes.md

Lines changed: 299 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,305 @@ Q: Why this document?
345345
This has some security implications too
346346
(eg. wrt on identifying parsers or treat downloads)
347347

348+
# Examples of content negotiation
349+
{: numbered="false" removeinrfc="true"}
350+
351+
This section explores the possibilities for User Agents
352+
to retrieve information about API specifications
353+
using their preferred version of OpenAPI.
354+
355+
## Scenarios
356+
{: numbered="false" removeinrfc="true"}
357+
358+
An API catalog exposes API specifications using OAS 3.0,
359+
and it wants to provide migration/upgrade capabilities
360+
to future versions of OAS and JSON Schema.
361+
For simplicity, we use only YAML serialization.
362+
363+
Resource: https://example.org/openapi.yaml
364+
: is an OpenAPI Specification document
365+
that references the Foo schema located at /foo.yaml.
366+
367+
~~~ http
368+
HTTP/1.1 200 OK
369+
Content-Location: openapi.yaml
370+
Content-Type: application/openapi+yaml; version=3.0
371+
372+
openapi: 3.0.0
373+
374+
components:
375+
schemas:
376+
Foo:
377+
"$ref": "/foo.yaml"
378+
~~~
379+
380+
~~~ http
381+
HTTP/1.1 200 OK
382+
Content-Location: openapi.yaml
383+
Content-Type: application/openapi+yaml; version=3.2
384+
385+
openapi: 3.2.0
386+
"$self": https://example.com/openapi.yaml
387+
388+
components:
389+
schemas:
390+
Foo:
391+
"$ref": /foo.yaml
392+
~~~
393+
394+
Resource: https://example.org/foo.yaml
395+
: is the schema definition for Foo,
396+
represented in two different ways
397+
depending on the OpenAPI version requested.
398+
399+
~~~ http
400+
HTTP/1.1 200 OK
401+
Content-Location: foo.yaml
402+
Content-Type: application/whatever+yaml
403+
404+
type: string
405+
enum: [ it, en]
406+
~~~
407+
408+
Since OAS 3.2 supports JSON Schema,
409+
the same syntax can be described
410+
adding a `title` to each enum value.
411+
412+
~~~ http
413+
HTTP/1.1 200 OK
414+
Content-Location: foo.yaml
415+
Content-Type: application/whatever+yaml
416+
417+
"$schema": "https://json-schema.org/draft/2020-12/schema"
418+
"$id": "https://example.com/foo.yaml"
419+
oneOf:
420+
- const: it
421+
title: Italian
422+
- const: en
423+
title: English
424+
~~~
425+
426+
### Scenario 1
427+
{: numbered="false" removeinrfc="true"}
428+
429+
The User Agent only supports OAS3.0
430+
and refuses other formats,
431+
including the more generic ones
432+
(see {{Section 12.4.3 of HTTP}}.
433+
434+
~~~ http
435+
GET /openapi.yaml HTTP/1.1
436+
Host: example.com
437+
Accept: \
438+
application/openapi+yaml; version=3.0,
439+
*/*; q=0
440+
~~~
441+
442+
The server responds with the desired resource.
443+
444+
~~~ http
445+
HTTP/1.1 200 OK
446+
Content-Type: application/openapi+yaml; version=3.0
447+
448+
openapi: 3.0.0
449+
450+
components:
451+
schemas:
452+
Foo:
453+
"$ref": /foo.yaml
454+
~~~
455+
456+
The User Agent processes the content
457+
and to resolve the `$ref`, requests the /foo.yaml.
458+
459+
It needs to retrieve a content compatible with
460+
the entry document.
461+
While the User Agent expects a JSON or YAML serialized content,
462+
compatible with OAS3.0,
463+
it cannot know the actual format that the server will return.
464+
465+
~~~ http
466+
GET /foo.yaml HTTP/1.1
467+
Host: example.com
468+
Accept: application/openapi+yaml; version=3.0; q=1, application/yaml; q=0.5
469+
~~~
470+
471+
The server responds with a YAML serialized content
472+
that is compatible with OAS3.0.
473+
Since the content only contains a Schema Object,
474+
that is not associated with any media type,
475+
the server uses the `application/yaml` media type.
476+
477+
~~~ http
478+
HTTP/1.1 200 OK
479+
Content-Type: application/yaml
480+
481+
type: string
482+
enum: [it, en]
483+
~~~
484+
485+
### Scenario 2
486+
{: numbered="false" removeinrfc="true"}
487+
488+
The User Agent prefers OAS3.2;
489+
moreover uses the `q` parameter
490+
to decline OAS3.0 documents.
491+
If it weren't so, the server
492+
could have responded with the older version
493+
if the OAS3.2 document were not available.
494+
495+
~~~ http
496+
GET /openapi.yaml HTTP/1.1
497+
Host: example.com
498+
Accept: application/openapi+yaml; version=3.2, application/openapi+yaml; version=3.0;q=0
499+
~~~
500+
501+
The server responds with the OAS3.2 document.
502+
503+
~~~ http
504+
HTTP/1.1 200 OK
505+
Content-Type: application/openapi+yaml; version=3.2
506+
507+
openapi: 3.0.0
508+
509+
components:
510+
schemas:
511+
Foo:
512+
"$ref": /foo.yaml
513+
~~~
514+
515+
The User Agent then requests the /foo.yaml,
516+
but it wants to retrieve a content with the most recent OAS version.
517+
518+
~~~ http
519+
GET /foo.yaml HTTP/1.1
520+
Host: example.com
521+
Accept: application/openapi+yaml; version=3.2
522+
~~~
523+
524+
The server processes the Accept header,
525+
and it realizes that the User Agent
526+
prefers an OAS3.2 compatible content.
527+
It then choses the JSON Schema representation
528+
and responds accordingly.
529+
530+
Since JSON Schema has no associated media type,
531+
the server uses the `application/yaml` media type.
532+
533+
~~~ http
534+
HTTP/1.1 200 OK
535+
Content-Type: application/yaml
536+
537+
"$schema": "https://json-schema.org/draft/2020-12/schema"
538+
"$id": "https://example.com/foo.yaml"
539+
oneOf:
540+
- const: it
541+
title: Italian
542+
- const: en
543+
title: English
544+
~~~
545+
546+
### Scenario 3
547+
{: numbered="false" removeinrfc="true"}
548+
549+
In this scenario:
550+
551+
1. the User Agent express preference
552+
for referenced resources compatible with OAS3.2.
553+
1. The server enforces a strict content negotiation,
554+
and responds with a 406 Not Acceptable;
555+
1. the User Agent will have to retry
556+
using one of the acceptable media types.
557+
558+
The User Agent prefers OAS3.2;
559+
moreover uses the `q` parameter
560+
to decline OAS3.0 documents.
561+
If it weren't so, the server
562+
could have responded with the older version
563+
if the OAS3.2 document were not available.
564+
565+
~~~ http
566+
GET /openapi.yaml HTTP/1.1
567+
Host: example.com
568+
Accept: application/openapi+yaml; version=3.2, application/openapi+yaml; version=3.0;q=0
569+
~~~
570+
571+
The server responds with the OAS3.2 document.
572+
573+
~~~ http
574+
HTTP/1.1 200 OK
575+
Content-Type: application/openapi+yaml; version=3.2
576+
577+
openapi: 3.0.0
578+
579+
components:
580+
schemas:
581+
Foo:
582+
"$ref": /foo.yaml
583+
~~~
584+
585+
The User Agent then requests the /foo.yaml,
586+
but it wants to retrieve a content with the most recent OAS version.
587+
588+
~~~ http
589+
GET /foo.yaml HTTP/1.1
590+
Host: example.com
591+
Accept: application/openapi+yaml; version=3.2
592+
~~~
593+
594+
The server processes the Accept header,
595+
and it realizes that foo.yaml is
596+
a JSON Schema document and not an OpenAPI document.
597+
598+
It then replies with the acceptable content.
599+
600+
~~~ http
601+
HTTP/1.1 406 Not Acceptable
602+
Accept: \
603+
application/whatever+yaml; version=https://json-schema.org/draft/2020-12/schema, \
604+
application/whatever+yaml; version=https://spec.openapis.org/oas/v3.0.4#schema-object
605+
~~~
606+
607+
The User Agent decides to retry the request
608+
using one of the acceptable media types.
609+
It could have also decided to give up.
610+
611+
~~~ http
612+
GET /foo.yaml HTTP/1.1
613+
Host: example.com
614+
Accept: \
615+
application/whatever+yaml; version=https://json-schema.org/draft/2020-12/schema
616+
~~~
617+
618+
Now the server can respond with the JSON Schema representation.
619+
620+
~~~ http
621+
HTTP/1.1 200 OK
622+
Content-Type: application/whatever+yaml; version=https://json-schema.org/draft/2020-12/schema
623+
624+
"$schema": "https://json-schema.org/draft/2020-12/schema"
625+
"$id": "https://example.com/foo.yaml"
626+
oneOf:
627+
- const: it
628+
title: Italian
629+
- const: en
630+
title: English
631+
~~~
632+
633+
Pros:
634+
635+
- The returned content is exactly what the User Agent requested.
636+
637+
Cons:
638+
639+
- Two requests were needed to retrieve the resource.
640+
- Some User Agents may not be able to handle
641+
the 406 Not Acceptable response and give up.
642+
- Requires a specific Accept value for each possible referenced resource,
643+
which may be difficult to manage.
644+
- Clients may not be able to
645+
646+
348647
# Change Log
349648
{: numbered="false" removeinrfc="true"}
350649

@@ -364,4 +663,3 @@ RFC EDITOR PLEASE DELETE THIS SECTION.
364663
{:numbered="false" removeinrfc="true"}
365664

366665
- Support OAS 2.0
367-

0 commit comments

Comments
 (0)