Den gode webservice
1. Formål og anvendelsesområde
Denne side fastlægger obligatoriske principper for udvikling af REST-services i DFDG.
Retningslinjerne gælder for:
Alle services udstillet af DFDG
Alle forretningsdomæner
Alle integrationer mod eksterne aftagere
REST er den eneste gældende integrationsform for synkrone services i DFDG.
2. Grundprincipper
En DFDG-service:
skal understøtte et klart afgrænset forretningsdomæne
må ikke udvikles specifikt til én aftager
skal kunne understøtte flere aftageres behov
skal være stabil og forudsigelig over tid
skal designes ud fra forretningskontekst – ikke teknisk convenience
Ét forretningsansvar pr. service.
En service kan være StatusService, Domæneservice eller RuleService jf. https://starwiki.atlassian.net/wiki/spaces/FYS/pages/1433370736.
StatusService udstiller aktuel status og overblik (ingen historik).
Domæneservice udstiller forretningsmæssige entiteter, CRUD og eventuel historik.
RuleService udstiller gældende forretningsregler og er ikke person- eller virksomhedsspecifik.
Valg af servicetype skal være eksplicit og begrundet i forretningsbehov.
3. REST-arkitektur
DFDG følger REST-principperne beskrevet i: https://starwiki.atlassian.net/wiki/spaces/CITY/pages/1406926851/Star.Foundation+-+Teknisk+dokumentation#REST-principper
Følgende er obligatorisk:
Ressourcer navngives som substantiver
HTTP-verber anvendes korrekt (GET, POST, PUT, DELETE)
PATCH understøttes ikke
JSON anvendes som dataformat
Routes versioneres via URL (v1, v2, …)
CRUD er udgangspunktet
Handlinger (actions)
Handlinger (/action/...) må kun anvendes når:
forretningslogik påvirker flere ressourcer samtidig
der udføres en samlet forretningsproces, som ikke kan udtrykkes som klassisk CRUD
der foretages søgninger, hvor søgeparametre er så mange eller så komplekse, at de ikke hensigtsmæssigt kan angives som query-parametre i et GET-kald
Actions må ikke anvendes som generel erstatning for CRUD.
4. Kontraktdesign og DTO-principper
4.1 Isolation af kontrakter
DTO’er:
må ikke genbruges mellem services
må ikke genbruges mellem versioner af samme service
må ikke deles på tværs af forretningsdomæner
Dette for at undgå:
utilsigtede breaking changes
kobling mellem services
påvirkning af eksterne aftagere
Kontrakten isoleres – ikke domænelogikken.
4.2 OIO-typer og valideringsattributter
For OIO-typer såsom CPR-nummer er der etableret dedikerede valideringsattributter, som kan anvendes til dekorering af properties i DTO’er.
Disse attributter sikrer ensartet syntaksvalidering på tværs af services og skal anvendes, hvor det er relevant.
Der må ikke etableres egne parallelle valideringsmekanismer for disse typer.
4.3 Forretningsmodel og logik
Den interne forretningsmodel og forretningslogik SKAL som udgangspunkt genbruges mellem versioner af samme service.
Det er udelukkende kontrakten (DTO’er og API-snitflade), der isoleres mellem versioner.
Versionering må ikke føre til:
duplikeret forretningslogik
parallelle domænemodeller
divergerende forretningsregler mellem versioner uden saglig begrundelse (lovændringer)
Lovændringer
Hvis ændret lovgivning medfører ændrede forretningsregler:
skal der etableres en ny serviceversion
den nye version må implementere de ændrede forretningsregler
tidligere versioner bevarer de forretningsregler, der var gældende ved versionens etablering
Der må ikke introduceres versionsafhængig forretningslogik inden for samme serviceversion.
Forretningsregler skal være konsistente og deterministiske inden for den enkelte version.
4.4 Borgerrelateret oprettelse og opdatering
Ved oprettelse eller opdatering af data, der direkte relaterer sig til en borger, skal personnummer indgå som en del af input.
Dette gælder uanset om:
der arbejdes på en entitet identificeret via GUID
entiteten allerede eksisterer
Personnummer skal indgå af hensyn til:
sikkerhed
sporbarhed
korrekt kontekstafgrænsning
RuleServices er undtaget, da de ikke er person- eller virksomhedsspecifikke.
5. Versionering
Versionering sker udelukkende via URL:
/v1/ressource
/v2/ressourcePrincipper:
Breaking changes kræver ny version
Non-breaking changes kan foretages uden versionsskift
Nuværende og forrige version skal kunne sameksistere
Udfasning varsles og aftales med aftagere
Kodelisteændringer kræver ikke versionsskift
5.1 Historik og GetHistory-principper
Historik udstilles kun, hvor der er et forretningsmæssigt behov.
En Domæneservice:
kan indeholde en særskilt GetHistory-metode
må ikke blande aktuel status og historik i samme respons
skal tydeligt adskille revisionshistorik fra liste-services
Der skal skelnes mellem:
Revisionshistorik (ændringer på samme entitet over tid)
Liste-services (kollektion af entiteter, hvor hvert element fremstår i seneste revision)
5.2 StatusService og historik
En StatusService må kun udstille aktuel status (og evt. planlagt/fremtidig status, hvis dette er relevant for forretningsmæssigt overblik).
En StatusService må ikke udstille:
afsluttede eller forhenværende forhold (historiske data)
revisionshistorik (ændringer over tid)
For tidsafgrænsede forhold gælder:
Aktuel status = forhold der pågår nu eller træder i kraft fremadrettet
Historik = forhold der er afsluttet og alene er relevante som tilbageblik
Hvis der er behov for afsluttede forhold eller revisionshistorik, skal dette udstilles via Domæneservice (Get/GetHistory) eller via en dedikeret liste-service
5.3 Konsistens og uforanderlighed over tid
Historik skal være konsistent med versioneringsprincipperne og må ikke ændre tidligere registrerede forretningsdata.
6. Dokumenthåndtering, herunder store dokumenter
6.1 Arkitekturprincip
DFDG har ét fælles dokumentarkiv i forretningsdomænet Dokumentarkiv.
Dokumentarkivet er eneste autoritative lagringssted gældende for dokumenter.
Andre forretningsdomæner må ikke etablere egne dokumentlagre.
6.2 Ansvarsfordeling
Forretningsdomæner med dokumentbehov:
skal selv udstille upload- og hent-services
må ikke eksponere Dokumentarkivets interne model
skal referere dokumenter via DocumentIdentifier (GUID)
Forretningsdomænet ejer forretningskonteksten.
Dokumentarkivet ejer dokumentet.
6.3 Kontraktprincipper
Dokumenter:
identificeres entydigt via GUID
må ikke oprettes med ugyldigt identifier
må ikke indlejres i generelle forretnings-DTO’er
skal hentes via dedikeret GET-endpoint
Dokumentindhold (fx binært indhold eller base64) må ikke returneres som en del af samlede forretningsobjekter eller større datasæt.
Det betyder, at dokumentindhold ikke må indgå i:
StatusServices
liste-services
søgeresultater
eller andre responser, der returnerer flere forretningsobjekter samlet
Dokumentindhold skal altid hentes via et særskilt, dedikeret endpoint.
6.4 Størrelse og type
Forretningsdomænet skal:
fastlægge maksimal dokumentstørrelse
validere dokumenttype
dokumentere begrænsninger i kontrakten
6.5 Adgang og events
Adgang følger det tilknyttede forretningsobjekt.
Dokumentindhold må ikke indgå i WSB’er
Events må kun indeholde reference (DocumentIdentifier)
Dokumentudlevering skal ske via autoriseret GET.
7. Validering og sanitering
7.1 Inputvalidering
Input skal valideres når:
datakvalitet påvirker borgerens rettigheder
sammenhænge i data er kritiske
data indgår i tilsyn eller målepunkter
7.2 HTML-sanitering (obligatorisk)
Alle tekstfelter:
saniteres for HTML og skadelige HTML tags
beskyttes mod XSS
Sanitering er en del af sikkerhedsmodellen – ikke kun datavalidering.
8. Sikkerhed og identifikation
Alle services:
skal følge DFDG’s gældende sikkerhedsmodel
skal identificere hvem der foretager kaldet
skal logge kald med korrelations-ID
Logning foretages via Star.Foundation, hvilket sikrer:
ensartet struktur
fælles korrelations-ID
ensartet metadata
centraliseret håndtering af logniveauer
Teams må ikke implementere egen alternativ logningsmekanisme for services.
Services må ikke udstilles uden adgangskontrol, medmindre de eksplicit er offentlige.
9. Webservicebeskeder (WSB)
DFDG anvender Webservicebeskeder (WSB) til asynkron kommunikation.
WSB’er:
pushes til aftagere
publiceres ved oprettelse, ændring eller sletning af relevante data
skal være konsistente med den synkrone REST-kontrakt
skal som hovedregel være uden body (ekstern data indhold)
må ikke indeholde fritekstfelter i bodý, når en sådan undtagelsesvist tillades
Synkron REST og asynkron WSB skal designes samlet, så:
hændelser afspejler faktiske forretningsændringer
aftagere kan reagere deterministisk
integrationer ikke kræver polling
10. Ændringer og varsling
Ved ændringer i servicesnitflader:
Breaking changes kræver ny version
Eksterne aftagere skal varsles
Ændringer skal accepteres før idriftsættelse
Samtidige ændringer hos alle aftagere skal undgås
Lovgivning kan undtagelsesvist kræve simultan ændring.
11. Anti-patterns (må ikke forekomme)
Service udviklet kun til én aftager
Genbrug af DTO mellem versioner
Breaking change uden ny version
Manglende sanitering af HTML
Overbelastede generiske services
SOAP-terminologi eller WSDL-tænkning