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

String velden - null of lege string of ... #2447

Open
basretera opened this issue May 24, 2024 · 24 comments
Open

String velden - null of lege string of ... #2447

basretera opened this issue May 24, 2024 · 24 comments
Labels

Comments

@basretera
Copy link

In onze testen met andere leveranciers lopen we tegen een issue aan m.b.t. optionele string velden. Via dit issue wil ik nogmaals vragen om een uitspraak te doen in hoe we hiermee om moeten gaan aangezien de standaard niet eenduidig is. Dit issue is in navolging op issue #1901 en issue #2090 aan. De standaard is gewoonweg niet duidelijk genoeg hierin. Wat moeten we nu doen met niet verplichte (string) velden? Opties die er zijn:

  1. Het veld weglaten in de request body;
  2. Opnemen maar met de waarde null; of
  3. Een lege waarde "" meegeven.

Optie 3 vind ik totaal niet fraai, maar het belangrijkste is dat er duidelijkheid komt. De voorgaande issues staan inmiddels 1,5 jaar open en iedere leverancier maakt hier zijn eigen keuzes in die mogelijkerwijs niet stroken met elkaar. Graag op korte termijn een uitspraak hierover zodat het voor alle leveranciers duidelijk is.

@basretera
Copy link
Author

Dit issue ligt alweer 7 dagen zonder enige reactie. Dit moet echt prioriteit krijgen. We lopen in onze testen hier zwaar tegenaan. Hier moet echt snel duidelijkheid over komen!

@HenriKorver
Copy link
Collaborator

Ik begrijp het issue niet goed. Kun je een concreet voorbeeld geven waar precies de problemen optreden?

@basretera
Copy link
Author

basretera commented May 31, 2024

image

In de specificatie van deze optionele stringvelden staat veelal bovenstaande (voorbeeld) gespecificeerd. Namelijk dat een veld een stringwaarde moet bevatten <= x karakters. Wat wordt hiermee bedoeld? Moeten deze optionele velden dan met een lege stringwaarde "" aangeboden worden? Logischer zou zijn dat deze een null-waarde zouden kunnen hebben. Null-waardes lijkt me toch een beetje de algehele standaard. Maar op andere plekken (zie hieronder) staat weer gespecificeerd string or null voor een vergelijkbaar veld.

image

En mag je optionele velden helemaal weglaten? Of moet je ze wel altijd teruggeven/meesturen maar dan inderdaad met een null-waarde of lege string-waarde ""?

Kijk ook zeker naar de lopende discussies in de gerelateerde issues.

@HenriKorver
Copy link
Collaborator

Namelijk dat een veld een stringwaarde moet bevatten <= x karakters. Wat wordt hiermee bedoeld?

Bijvoorbeeld <= 80 betekent dat de string niet langer mag zijn dan 80. Dus de string mag wel een lengte 0 hebben, oftewel leeg zijn.

@basretera
Copy link
Author

basretera commented May 31, 2024

Dat snap ik natuurlijk ook. Maar daar gaat het niet om.

@HenriKorver
Copy link
Collaborator

HenriKorver commented May 31, 2024

En mag je optionele velden helemaal weglaten? Of moet je ze wel altijd teruggeven/meesturen maar dan inderdaad met een null-waarde of lege string-waarde ""?

In principe mag je zelf bepalen of je lege attributen die niet required zijn wel of niet opneemt in een bericht. In een request bericht laat ik de lege attributen altijd weg als ze niet verplicht zijn, lijkt me logisch want waarom zou ik de moeite doen. Echter, bij een respons-bericht vind ik het wel weer prettig als ook de attributen met een lege waarde worden teruggegeven, want dan zie ik namelijk in één oog opslag welke attributen wel of niet gevuld zijn. De referentie-implementatie doet het ook zo.

@basretera
Copy link
Author

Dank voor je antwoord, maar het geeft nog steeds geen antwoord op de meest prangende vraag: moet een leeg veld als lege string "" of als null-waarde in een request meegegeven en in een response teruggegeven worden?

@HenriKorver
Copy link
Collaborator

HenriKorver commented May 31, 2024

In de meeste gevallen zijn de attributen zo gespecificeerd dat er maar één waarde voor het leeg zijn mogelijk is, dus of null of "" (lege string), maar niet beide. Dus daar speelt dit probleem niet. Helaas zijn er een paar gevallen waarbij dit niet goed is gegaan zoals bij het attribuut "processobjectaard". In dat geval moet de API beide waarden ondersteunen (null en lege string). Het is niet fraai maar het werkt wel.

Bij het toevoegen van nieuwe attributen in toekomstige versies moeten we goed in de gaten houden dat we slechts één leeg-waarde toelaten. De vraag is of we in een volgende major release ook alle oude attributen waar dit probleem speelt willen fixen (lees: beperken tot één leeg-waarde) want dat zal mogelijk tot veel backwards compatibiliteits problemen kunnen leiden.

@basretera
Copy link
Author

basretera commented Jun 3, 2024

Laatste vraag: Kun jij mij uitleggen waarom er gekozen is voor een lege string "" waarde i.p.v. null? Wat veel logischer lijkt voor mij. Is dat in REST API standaarden gebruikelijker of wat is de reden?

@HenriKorver
Copy link
Collaborator

HenriKorver commented Jun 3, 2024

Ik weet niet wat de exacte beweegredenen waren om te kiezen voor een lege string "" i.p.v. null en ik weet ook niet wat de beweegredenen waren om daar weer soms van af te wijken zoals bij het attribuut 'processobjectaard'. Dat was voor mijn tijd. Het niet consequent zijn is een groter probleem dan de waarom-vraag denk ik.

Persoonlijk vind ik het mooier als attributen van het type "string" een lege string "" als lege waarde teruggeven en niet null. Het is namelijk een lege waarde die het datatype string al van zichzelf heeft en je hoeft dan geen nieuw concept zoals null te introduceren. Hetzelfde verhaal voor attributen van het type "array": die geeft je de lege lijst [] terug en niet de waarde null. Immers het datatype array heeft intrinsiek een eigen lege waarde namelijk de lege lijst [] net zoals string ook zijn eigen lege waarde heeft namelijk de lege string "".
Het mooie is dan ook dat je in de respons-berichten kunt zien van welke type het lege attribuut is ("" -> string, [] -> array). Dit vind ik fijner dan dat er null had gestaan.

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "url": "https://zaken-api.vng.cloud/api/v1/zaken/01a50969-359c-4a0e-95ca-79293914534b",
            "uuid": "01a50969-359c-4a0e-95ca-79293914534b",
            "identificatie": "ZAAK-2019-0000000002",
            "bronorganisatie": "000000000",
            "omschrijving": "aangepast",
            "toelichting": "string",
            "zaaktype": "https://catalogi-api.vng.cloud/api/v1/zaaktypen/f0cdd277-c62d-4464-a0a7-ddffd6d29f6b",
            "registratiedatum": "2019-04-09",
            "verantwoordelijkeOrganisatie": "000000000",
            "startdatum": "2019-04-09",
            "einddatum": null,
            "einddatumGepland": "2019-04-20",
            "uiterlijkeEinddatumAfdoening": "2019-04-09",
            "publicatiedatum": "2019-04-09",
            "communicatiekanaal": "",
            "productenOfDiensten": [],
            "vertrouwelijkheidaanduiding": "openbaar",
            "betalingsindicatie": "geheel",
            "betalingsindicatieWeergave": "De met de zaak gemoeide kosten zijn geheel betaald.",
            "laatsteBetaaldatum": null,
            "zaakgeometrie": {
                "type": "Point",
                "coordinates": [
                    53.0,
                    5.0
                ]
            },
            "verlenging": {
                "reden": "",
                "duur": null
            },
            "opschorting": {
                "indicatie": true,
                "reden": "string"
            },
            "selectielijstklasse": "https://referentielijsten-api.vng.cloud/api/v1/resultaten/fb65ae34-e820-4ace-815a-cf5da7d04a12",
            "hoofdzaak": null,
            "deelzaken": [],
            "relevanteAndereZaken": [],
            "eigenschappen": [
                "https://zaken-api.vng.cloud/api/v1/zaken/01a50969-359c-4a0e-95ca-79293914534b/zaakeigenschappen/e5235521-e735-40a3-8005-2b9953757c2c"
            ],
            "rollen": [],
            "status": null,
            "zaakinformatieobjecten": [],
            "zaakobjecten": [],
            "kenmerken": [],
            "archiefnominatie": null,
            "archiefstatus": "nog_te_archiveren",
            "archiefactiedatum": null,
            "resultaat": null,
            "opdrachtgevendeOrganisatie": "",
            "processobjectaard": null,
            "startdatumBewaartermijn": null,
            "processobject": {
                "datumkenmerk": "",
                "identificatie": "",
                "objecttype": "",
                "registratie": ""
            }
        }
    ]
}

In mijn ogen is de definitie van het attribuut "processobjectaard" een designfout en had er een lege string "" teruggegeven moeten worden in plaats van null. Want alle andere attributen van het type string geven wel een lege string "" terug zoals datumkenmerk, identificatie, objecttype , etc.

@sergei-maertens
Copy link
Collaborator

OpenAPI maakt gebruik van JsonSchema (ze zijn niet 100% gelijk, maar bewegen wel die kant op), dus om deze vraag te beantwoorden moet je naar de details van JsonSchema kijken. Een eenvoudig voorbeeld:

type: object
required:
  - property1
properties:
  property1:
    type: string
    maxLength: 80
  property2:
    type:
      - string
      - 'null'
    maxLength: 20
  • required betekent dat deze attributen (property1) altijd aanwezig moeten zijn. {} is dus niet valide, {"property1": ""} en {"property1": "", "property2": ""} zijn dat wel. Required zegt nooit iets of een lege waarde toegestaan is of niet, alleen of er een garantie is dat de key aanwezig is of niet.
  • property1 heeft als mogelijke datatypes (meervoud belangrijk!) enkel string, met hierboven een extra restrictie: maximaal 80 karakters. Dus, deze mag een lege string zijn, maar mag niet afwezig zijn en mag niet langer dan 80 karakters zijn.
  • property2 heeft als mogelijke datatypes string en null. Dus, als de property aanwezig is, dan mag die null zijn, en als die een string is, dan mag die een lege string zijn of maximaal 20 karakters tellen. De property mag ook helemaal afwezig zijn.

Extra validates zijn altijd bovenop het type waarop de validatie betrekking heeft. maxLength heeft geen betekenis voor null, en is dus niet relevant. Een property die niet required is, mag enkel als null meegestuurd worden als het type van de property null toestaat.

In OpenAPI 3.1 gebruiken ze deze array voor types, voor eerdere versie is hier de nullable: true schema key beschikbaar (even uit het hoofd).

De volgende ("lege") data objecten zijn dus wel geldig voor het schema hierboven:

{"property1": ""}
{"property1": "", "property2": ""}
{"property1": "", "property2": null}

Dit is een onderwerp waar veel verwarring over bestaat, maar het is wel gespecifieerd in de onderliggende JsonSchema specificatie.

@sergei-maertens
Copy link
Collaborator

@HenriKorver

Persoonlijk vind ik het mooier als attributen van het type "string" een lege string "" als lege waarde teruggeven en niet null. Het is namelijk een lege waarde die het datatype string al van zichzelf heeft en je hoeft dan geen nieuw concept zoals null te introduceren. Hetzelfde verhaal voor attributen van het type "array": die geeft je de lege lijst [] terug en niet de waarde null. Immers het datatype array heeft intrinsiek een eigen lege waarde namelijk de lege lijst [] net zoals string ook zijn eigen lege waarde heeft namelijk de lege string "".

Hier zit wel nuance die relevant kan zijn! null is een weergave dat er niets gezet is, het is onbekende informatie. Terwijl een lege array [] gewoon kan betekenen dat er wel iets gezet is, maar er is geen relevante informatie. null lees je typisch als "onbepaald", in plaats van "leeg". Tri-state logica kent bijvoorbeeld true | false | null om dit weer te geven.

@basretera
Copy link
Author

@sergei-maertens Dank voor je heldere uiteenzetting!

@erikhoevenberg
Copy link

Bovenstaande maakt het een en ander duidelijk maar ik heb nog een vervolg vraag. Is "" een geldige waarde voor een url/datum/duration? Voor enum kan ik afleiden dat dit niet het geval is omdat er soms expliciet een "Empty Enum" optie staat gespecifieerd.

@basretera basretera reopened this Jul 1, 2024
@sergei-maertens
Copy link
Collaborator

sergei-maertens commented Jul 1, 2024

Voor de zekerheid heb ik het zelf even getoetst op https://www.jsonschemavalidator.net/, met schema:

{
  "type": "string",
  "format": "date-time"
}

en waarde:

""

en deze is inderdaad niet geldig. Daarom zou je dus typisch wel null toelaten om een onbekende waarde te communiceren.

Alledrie de voorbeelden die je noemt zijn ongeldig met lege-string.

@erikhoevenberg
Copy link

Moeten wij in plaats van null een lege string teruggeven als bijvoorbeeld de toelichting op een zaak niet gespecificeerd is?

Zelf vind ik dit niet logisch namelijk omdat dit niet de waarde is die origineel is opgegeven. Daarbij moet de api dan zelf een onbekende waarde mappen op "" wat ik als ontwikkelaar irritant vind omdat het een extra stukje complexiteit toevoegt. Verder zou het inconsistent zijn met strings die een bepaald formaat hebben, die kunnen immers niet "" zijn zoals hierboven vastgesteld. Tenzij er bewust voor wordt gekozen af te wijken van hoe json schema’s normaal gesproken werken.

@HenriKorver, zou jij je antwoord nog eens kunnen bekijken? Ik volg je redenering maar ik vraag me af of het handig is.

@sergei-maertens
Copy link
Collaborator

sergei-maertens commented Jul 9, 2024

toelichting kan nooit null zijn in de response, want de API spec laat het niet toe, maar zo te zien wordt dat niet netjes gerenderd op zaken-api.vng.cloud

Dezelfde spec uit Open Zaak:

image

v.s. een veld wat wel null kan zijn:

image

Dus voor een toelichting die niet opgegeven is kan de enige geldige waarde de lege string "" zijn.

Ik zie niet in hoe dat inconsistent is of hoe mijn comment dat zou reflecteren - toelichting is gewoon een string met als validatieregel "tussen de 0 en 1000 karakters", dus een lege string voldoet daaraan.

Mijn voorbeeld geeft een string met als formaat date-time, en daar voldoet een lege string NIET aan, maar toelichting specifieert geen bepaald formaat, dus dat is een beetje appels en peren vergelijken.

@HenriKorver
Copy link
Collaborator

@erikhoevenberg, helaas kan ik mijn antwoord niet herzien, zie bovenstaande uitleg van @sergei-maertens

@HenriKorver
Copy link
Collaborator

..., maar zo te zien wordt dat niet netjes gerenderd op zaken-api.vng.cloud

@sergei-maertens Wat gaat er precies mis met de rendering op zaken-api.vng.cloud, want ik kan dat hier niet reconstrueren?

@erikhoevenberg
Copy link

erikhoevenberg commented Jul 9, 2024

Ik snap het en dan is het antwoord op mijn vraag dus gewoon ja.

Als ik de standaard nu letterlijk neem ben ik niet in staat om bijvoorbeeld communicatiekanaal leeg te maken via de PATCH. Want null is geen optie en een lege string ook niet. Ik kan hem wel via de PUT updaten en dan simpelweg het veld weglaten. Dit lijkt me niet de bedoeling en zou worden opgelost als null wel was toegestaan.

Ik zou zelf liever zien dat null altijd was toegestaan voor een string, tenzij er een functionele reden is waarom het gevuld moet zijn natuurlijk. Maar ik schat zo in dat ik op dit punt geen gelijk ga krijgen.

Ik was er vanwege de opmerking van Sergei vanuit gegaan dat null impliciet een mogelijk waarde was op communicatiekanaal, maar dat is natuurlijk niet zo.

Overigens geeft de referentie implementatie en lege string terug bij communicatiekanaal.

We kunnen hier wel mee verder in ieder geval. Dankjulliewel voor de uitleg.

@sergei-maertens
Copy link
Collaborator

..., maar zo te zien wordt dat niet netjes gerenderd op zaken-api.vng.cloud

@sergei-maertens Wat gaat er precies mis met de rendering op zaken-api.vng.cloud, want ik kan dat hier niet reconstrueren?

My bad, de null voor einddatum staat er wel, in nieuwere redoc versies staat die alleen wat prominenter in beeld!

@basretera
Copy link
Author

Voor de zekerheid heb ik het zelf even getoetst op https://www.jsonschemavalidator.net/, met schema:

{
  "type": "string",
  "format": "date-time"
}

en waarde:

""

en deze is inderdaad niet geldig. Daarom zou je dus typisch wel null toelaten om een onbekende waarde te communiceren.

Alledrie de voorbeelden die je noemt zijn ongeldig met lege-string.

@HenriKorver: Hoe moeten we nu met de genoemde voorbeelden omgaan? Volgens Sergei zijn lege stringwaarden ("") in genoemde voorbeelden (URL/Date-time/Duration) geen geldige waarden. Hoe kunnen we deze velden nu dan fatsoenlijk ondersteunen bij POST/PUT/PATCH? Enige optie die ik op dit moment zie, is daadwerkelijk het veld weglaten aangezien het een optioneel veld is. Hoe zie jij dit?

@HenriKorver HenriKorver moved this from Done to In Progress in Kanban bord API's voor Zaakgericht werken Aug 19, 2024
@HenriKorver
Copy link
Collaborator

@basretera Ik begrijp je probleem niet zo goed. Kun je een concreet voorbeeld geven waar je deze velden niet fatsoenlijk kunt ondersteunen bij POST/PUT/PATCH?

@basretera
Copy link
Author

basretera commented Aug 19, 2024

@HenriKorver: zie citaat en eerdere reacties van @sergei-maertens. Een lege string "" is geen geldige URL volgens json schema validator. Dit geldt ook voor date-time en duration velden. M.a.w. zou het dus eigenlijk niet geaccepteerd moeten worden dat een URL-veld zoals bijvoorbeeld "communicatiekanaal" een lege string mag bevatten. Je laat het veld dus weg, of je geeft als clientapplicatie ook daadwerkelijk een geldige URL mee als waarde of null.

Als we er niet uitkomen, zou ik willen opteren voor een mondeling overleg met wat belanghebbenden/betrokkenen.

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

No branches or pull requests

4 participants