Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback op ADR #639

Open
arucard21 opened this issue Nov 19, 2024 · 2 comments
Open

Feedback op ADR #639

arucard21 opened this issue Nov 19, 2024 · 2 comments

Comments

@arucard21
Copy link

Ik heb gerecent geprobeerd de ADR te volgen in een Proof-of-Concept API om uit te zoeken hoe goed dit aansluit op de APIs in onze organisatie en dat blijkt vrij goed aan te sluiten. Er zijn wel wat punten waar ik feedback op wil geven, dus dat doe ik hier met dit issue. Deze feedback staat grotendeels, en met meer detail, ook beschreven bij de documentatie van de PoC API (in het Engels).

De /core/no-trailing-slash regel leek mij overbodig en kan juist verwarrend zijn. URIs met wel of geen trailing slash zijn equivalent aan elkaar. Dit is zo gedefinieerd in de URI specificatie. Het lijkt me verwarrender om daar tegen in te gaan en af te dwingen dat je deze URIs als verschillend ziet. Ook zijn er andere URIs die equivalent kunnen zijn, zoals http://localhost/resources en http://localhost:80/resources en http://localhost:/resources. Geen van deze URIs hebben een trailing slash, maar zijn wel equivalent. Hierdoor bereikt deze regel zijn beoogd doel ook niet.

De /core/version-header regel vond ik niet perse verkeerd, maar ook deze leek overbodig. Je moet de versie van de API namelijk al documenteren in het OpenAPI Specification document. Er is hier een verplicht veld voor gedefinieerd, namelijk info.version. Het lijkt mij logischer om de API versie alleen daar te definieren, aangezien het hetzelfde is voor de hele API. Hiermee vermijd je ook de tijd en moeite om de API-Version header te documenteren en implementeren, en de mogelijkheid dat de versie in de API-Version afwijkt van de versie in OpenAPI.

Versioning

Het versioning mechanisme kan, naar mijn mening, beter. Ik zag dat dit al vaker besproken was in issues, en in #280 (comment) wordt een lijst van de meest gebruikelijke mogelijkheden genoemd. Ik begrijp dat de gekozen versie, een major versie nummer in de URI, vaker gebruikt wordt en daardoor bekend is. Maar ik denk dat die manier van versioning een fundamenteel probleem heeft, en dat versioning via media type, met gebruik van content negotiation, een veel krachtiger en flexibeler mechanisme is. En dat wil ik hier beargumenteren.

De nadelen die in dat issue genoemd worden voor versioning via media type, zijn dat elke versie een nieuwe media type vereist en dat geen gebruik gemaakt worden van standaard media types. Dat eerste is waar, hoewel ik dat niet perse als een nadeel zie. Het maken van een nieuwe media type, als deze unregistered is, vereist vrijwel geen werk. Het werk zit in het documenteren van het gedrag van de media type, dus het documenteren van de nieuwe versie van je API resource. Dit is iets wat sowieso moet gebeuren voor een nieuwe versie.

Het andere nadeel is dat er geen gebruik gemaakt kan worden van standaard media types. Dit hoeft niet zo erg te zijn als het lijkt. Het gebruik van unregistered media types van de vorm application/x.custom-media-type is namelijk een onderdeel van de standaard. Je kan hier de structured suffix voor JSON op toepassen en ook de major versie in verwerken om tot application/x.custom-media-type-v1+json te komen. Dit is een custom media type die volledig aan de standaard voldoet en nog steeds aangeeft dat het een JSON document is. Er kunnen ook andere formaten dan JSON aangegeven worden met de structured suffix, zoals YAML of XML.

Het blijft echter mogelijk om standaard media types te gebruiken, maar dan media types gemaakt voor APIs. Zowel HAL+JSON als JSON-LD ondersteunen een media type parameter profile. Hierin kan je de naam van je API resource verwerken, bijvoorbeeld application/hal+json;profile="my-api-resource-v1". Je ziet dat je hier, net als bij de custom media type een major versie in de naam kan verwerken. Het enige nadeel hierbij is dat ik gemerkt heb dat media type parameters, zoals profile hier, niet goed ondersteund worden in tooling. Het kan dus zo zijn dat de profile parameter op application/hal+json;profile="my-api-resource-v1" en application/hal+json;profile="my-api-resource-v2" genegeerd wordt en deze als hetzelfde gezien worden. Ik weet dat dit in JAX-RS zo is en het is tot nu toe mij niet gelukt om dit aangepast te krijgen.

Zoals eerder gezegd, is content negotiation een krachtig en flexibel mechanisme voor versioning. Tijdens een migratie naar een nieuwe versie kan een client heel makkelijk terugvallen op een oudere versie door een Accept header toe te voegen. Dit maakt de migratie een stuk gebruikersvriendelijker. Ook is er de optie om gebruikers vroegtijdig een nieuwe versie te laten gebruiken, door v2 alleen terug te geven als dat expliciet in de Accept header gevraagd wordt. En soms hoeft de client nieteens aangepast te worden tijdens de migratie. Het kan namelijk dat de breaking changes voor de major versie gemaakt zijn in een deel van de API dat niet gebruikt wordt door die specifieke client. Dus de client kan de nieuwe versie van de API resource gebruiken, zonder daar iets voor te hoeven aanpassen.

Dit brengt me tot het fundamenteel probleem met versioning in de URI. En daar wordt een beetje naar verwezen in het nadeel dat genoemd wordt voor deze manier van versioning in #280. Het wordt namelijk vrijwel onmogelijk om een eenduidige verwijzing te hebben naar een API resource. Want zowel http://localhost/v1/resources/1234 als http://localhost/v2/resources/1234 verwijzen naar dezelfde API resource. En in de toekomst, als er een v3 of v4 API is, is het heel goed mogelijk dat beide verwijzingen niet meer werken, ook al blijft de API resource bestaan.

Dit komt ook terug in de aanbevelingen van het W3C over URIs en resources. Er wordt namelijk aanbevolen dat er een goed onderscheidbare URI gekozen wordt voor elke resource. Ook wordt er aanbevolen dat er geen verschillende URIs gebruikt worden om naar dezelfde resource te verwijzen. Maar dat is precies wat hier gebeurt. En het leidt dus tot verwarring over wat nou de URI naar een resource hoort te zijn en maakt het onmogelijk om eenduidig te verwijzen naar een API resource.

Het is echter niet te vermijden dat deze manier van versioning minder gebruikelijk is, en dus ook minder bekend bij developers. Dit is het grote voordeel van versioning in de URI. Maar content negotiation is een gestandaardiseerd onderdeel van de HTTP specificatie. Veel van de API tooling heeft dus al ondersteuning hiervoor. Met JAX-RS wordt bijvoorbeeld de Accept header al standaard meegenomen wanneer een request verbonden moet worden aan de implementatie, en je kan server-side voorkeuren aangeven in de code om daar meer invloed op uit te oefenen. Dus ook al is versioning via content negotiation minder bekend, er hoeft ook minder voor gedaan te worden om het te implementeren.

Ik hoop dat deze feedback op prijs gesteld wordt, en ook nuttig is voor jullie. Ik denk zeker dat de ADR heel nuttig is, en ik denk dat ik de linter en validator al kan gebruiken om de kwaliteit van onze APIs te verbeteren in onze organisatie. Als er nog vragen zijn over de feedback die ik heb gegeven, hoor ik het graag.

@dvh
Copy link
Collaborator

dvh commented Nov 25, 2024

Wat betreft het info.version veld; deze is niet bedoeld om de versie van de API aan te geven:

The version of the OpenAPI Document (which is distinct from the OpenAPI Specification version or the version of the API being described or the version of the OpenAPI Description).

Zie ook #626 en #622.

Wat betreft de keuze voor major versienummer in de URI weet ik in ieder geval dat daar ellenlange discussies over hebben plaatsgevonden en er uiteindelijk gewoon een keuze is gemaakt omdat er anders waarschijnlijk nu nog steeds geen standaard was 😉

@arucard21
Copy link
Author

Dat klopt inderdaad, over het info.version veld. Ik heb dat blijkbaar verkeerd gelezen.

Ik herken ook de lange discussies over versioning, dus ik begrijp dat er uiteindelijk een knoop doorgehakt is. Een voordeel van de manier van versioning die ik hier beschrijf, is dat het geen conflict heeft met het versie nummer in de URL. Dat laatste kan gezien worden als de manier van versioning voor de hele API. En de manier van versioning die ik hier beschrijf, is aanvullend daarop, en gericht op de API resources. Als dit eenmaal goed geimplementeerd is, zou de hele API dan minder vaak (of vrijwel nooit) een versie update nodig hebben.

Het moet wel discoverable zijn wanneer deze resource-versioning beschikbaar is, en dat zou al moeten blijken uit het OAS document. Daarin zouden, voor een specifiek pad en HTTP methode, meerdere media types beschikbaar moeten zijn, met elk een andere versie van de resource.

Dit neemt niet weg dat deze suggestie weer ellenlange discussies kan starten, dus ik begrijp als niemand daar zin in heeft. Voor de gebruiker van de API denk ik dat het wel fijner is om meer opties te hebben, zeker als je daarmee de kans op het breken van je client door versie updates kan verminderen. Dus ik wilde dit tenminste als optie aandragen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants