Denne guide har til formål at give anvendere et overblik af NAP SDK'et, dets indhold og dets anvendelse.
Anvendere af NAP-SDK er primært projektudviklere, hvilket betyder at denne guide er egnet til dem.
Der foreligger desuden anvendelseseksempler. På baggrund af følgende eksempler, er det muligt at komme hurtigt i gang med anvendelsen af SDK'erne.
Dette dokument er en del af den samlede dokumentation for NAP SDK.
Dokumentet er udformet, så det i videst muligt omfang opfylder sit formål uafhængigt af de øvrige dokumenter.
Ønskes mere information omkring arkitektur og design findes dette på NAP SDK - Design og Arkitektur beskrivelse.
Ønskes mere information omkring installationsvejledning til anvendere findes dette på NAP SDK - Installationsvejledning.
Nap-typescript-sdk er det basale SDK. Det udstiller en række metoder og interfaces som bliver beskrevet nedenfor.
En wrapper af NAP Bridge, som et værtssytem ligger på global scope af den embeddede browser.
export interface NAP { fromHost$: Observable<NAPMessage>; toHost$: Subject<NAPMessage>; errors$: Observable<NAPError>; subscribe: (subscriber: NAPHostSubscriber) => void; unsubscribe: (subscriber: NAPHostSubscriber) => void; send: (message: NAPMessage) => void; } |
Navn | Forklaring |
---|---|
fromHost$ | Beskeder af NAPMessages fra værtssystemet. Udstillet som en Observable. |
toHost$ | Send en NAPMessage til hosten. Denne er udstillet som et subject, som man kan skubbe beskeder til med next(). |
errors$ | SDK fejl, udstillet som en Observable. |
subscribe | Subscriber til NAPMessages fra værtsystemet. Det fungere på samme måde som med `fromHost$`, bare uden brug af observables. |
unsubscribe | Unsubscribe af NAPMessages fra værtssystemet. |
send() | Send en NAPMessage - Det fungerer på samme måde som to `toHost$`, bare uden brug af observables. |
Denne wrapping foregår i createNAP() funktion, som SDKet eksporterer. En NAP bro kan således fanges gennem sdket ved et simpel kald:
import { createNAP, NAP} from "nap-typescript-sdk"; const nap:Nap = createNAP(); |
Den grundlæggende model for nap beskeder, der kører over (fromHost$, toHost$, subscribe og send).
Består af følgende felter, hvor context propertien, er meget inspireret af FHIR / FHIRcast (https://fhircast.org/specification/Feb2020Ballot/).
export interface NAPMessage { date: string; id: string; event: NAPEvent; } export interface NAPEvent { type: NAPEventType; context?: FHIR.Context[]; } export interface Context { resource?: { resourceType: string; meta?: Meta; code?: { coding: Coding[]; }; name?: Name[]; identifier?: Identifier[]; extension?: Extension[]; }; } export interface Name { family: string; given: string[]; } export interface Extension { url: string; value: string; } export interface Identifier { system: string; value: string; } export interface Coding { system: string; code: string; } export interface Meta { profile: string[]; } |
Eventkataloget definerer de eventtyper, der kan sendes over NAP i en given version.
Der er fortaget en minimal implementation af FHIR for at kunne opfylde nedenstående eventkatalog.
I SDKet sker der tjek på at følgende felter opfylder dataformatet:
NapMessage Felt | |
---|---|
date | ISO 8601-2 eksempelvis: 2020-06-22T08:07:18.892Z |
id | UUID eksempelvis: 4ddabe25-5f7a-4bce-89c1-f017cf2bc569 |
Er det ikke tilfældet sendes en sessionError til værtssystem og der sendes en fejlbesked på error$ (stream med error beskeder), som de indlejrede system kan lytte på.
Dette eventkatalog lægger sig op af FHIR / FHIRcast.
Eventkatalog version 1 | |
NAPEventType | Funktionelle beskrivelse |
---|---|
SessionOpen | Start en trusted session hvor brugerens SAMLassertion overføres |
SessionClose | Hvis en bruger ønskes lukkes ud. Alt state skal slettes på web-applikationen |
WebAppOpen | Sendes udelukkende fra lobbyen. Anvendes når en bruger vælger en afprøvningsløsning i lobbyen |
PatientOpen | Den brugervalgte patient journal. |
PatientClose | Den brugervalgte patient journal lukkes. |
SessionError | Hvis der sker en uventet fejl i sessionen (http errors / fejl i dataformatet eller lignende) sendes dette til værtssystemet og vice versa. |
Som i FHIRCast definerer eventtypen dataformatet. Eksempler på disse events er illustreret nedenfor.
Dog er WebAppOpen ikke beskrevet i dette dokument, da dette event er tilegnet kommunikation lobby-værtssytem. Du kan finde mere information om dette event på NAP Platform - Guide til anvendere.
import { NAPEventCatalogue } from 'nap-typescript-sdk'; const sessionCloseEvent = NAPEventCatalogue.v1.SessionClose; |
Model for de SDK fejl. Disse beskeder sendes, hvis sker der fejl i createNAP() kaldet - når NAP bridge skal wrappes.
export interface NAPError { id: number; message: string; isFatal: boolean; } |
Fejl bliver således skrevet i web konsollen.
this.napAngular.errors$.subscribe(res => { console.error(res); }); |
Eksemplet er taget fra NapRefWeb Referenceimplementering (NAP) - Leverancebeskrivelse.
Nap-typescript-sdk indeholder derudover en række hjælpefunktioner, som kan være brugbare til at hente værdier eller undgå stavefejl, når der skal laves NAPMessages.
Komplet liste over hjælpefunktioner:
Funktion | |
---|---|
getSessionValue(napMessage: NAPMessage): string | undefined | Henter samlAssertion. Returnerer undefined, hvis ikke data kan formateres. |
getPatientInfo(napMessage: NAPMessage): NAPPatientInfo | undefined | Henter patientinfo. Returnerer undefined, hvis ikke data kan formateres. |
filterEvents(type: string): Observable<NAPMessage> | Filtrer på et array eventtypes. Returnerer en observable, der kun emitter, når et event med en af de angivne typer emittes fra source. |
filterEvent(type: string): Observable<NAPMessage> | Filtrer på en event. Returnerer en observable, der kun emitter, når et event med en den angivne type emittes fra source. |
Funktioner, som gør det lettere at hente FHIR specifikke værdier ud af en NAPMessage. Disse kan bruges ved at importere namespacet FHIRValueGetter.
Følgende eksempel mapper en NAPMessage til en SAMLassertion og PatientInfo.
import { FHIRValueGetter, NAPMessage, NAPPatientInfo } from 'nap-typescript-sdk'; const sessionToken = FHIRValueGetter.getSessionValue(napMessage); const patientData: NAPPatientInfo = FHIRValueGetter.getSessionValue(napMessage); |
import {filterEvents, NAPEventCatalogue} from 'nap-typescript-sdk'; nap.incoming$.pipe( filterEvents([ NAPEventCatalogue.v1.SessionOpen, NAPEventCatalogue.v1.SessionClose, ]) ) |
Enums som gør det nemmere at lave NAPMessages indholdende de værdier, som overholder FHIR standarden.
Komplet liste over hjælpeværdier.
Enum |
---|
FHIRResourceType.Patient |
FHIRResourceType.Basic |
FHIRSystem.NAP |
FHIRIdentifierSystem.CPR |
FHIRIdentifierSystem.NAPErrorMessage |
FHIRIdentifierSystem.NapErrorDescription |
Følgende er et eksempel hvordan der sendes en fejlbesked.
import {NAPMessage, NAPEventCatalogue, FHIRValueSetter} from 'nap-typescript-sdk'; import { v4 as UUID } from 'uuid'; const napMessageSessionError: NAPMessage = { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.SessionError, context: [ { resource: { resourceType: FHIRValueSetter.FHIRResourceType.Basic, code: { coding: [ { code: NAPEventCatalogue.v1.SessionError, system: FHIRValueSetter.FHIRSystem.NAP, }, ], }, identifier: [ { system: FHIRValueSetter.FHIRIdentifierSystem.NAPErrorMessage, value: 'This is my error message', }, { system: FHIRValueSetter.FHIRIdentifierSystem.NAPErrorDescription, value: 'This is a longere description of the error message', }, ], }, }, ], }, }; NapTypescriptSdk.send(napMessageSessionError) |
Hvis du ønsker at bruge Angular som udviklingsværktøj.
Da nap-angular-sdk er en angular specifik wrapper af nap-typescript-sdk, er der en peer dependency til samme version af dette SDK.
NAP-angular-SDK udstiller en service, som sørger for at kalde createNAP() fra nap-typescript-sdket og dermed initialisere kontekstbroen.
Efterfølgende subscribes der på de forskellige messagestreams, og deres emits bliver håndteret i forhold til Angulars change detection zone.
Udfra dette generer den nye observables som er tilgængelig som public felter.
NapAngularService { // attributter incoming$: Observable<NAPmessage> errors$: Observable<NAPError> outgoing$: Subject<NapMessage> sendMessage(message: NAPMessage):void subscribeToMessages(callback: (message: NAPMessage) => void): void } |
Effekten for anvenderen bliver, at broen initialiseres som en singleton og at Angular opfanger beskeder sendt over broen og opdaterer UI på baggrund af disse værdier.
Generel kodedokumentation findes i biblioteket. Fuld implementation af eventkataloget ses i nap-reference-web her https://svn.nspop.dk/svn/components/nap/nap-reference-web/trunk/.
Følgende eksempel sender en Session-Open besked og får en SAMLassertion tilbage:
import { NapAngularService } from 'nap-angular-sdk'; import { filterEvents, NAPEventCatalogue, NAPMessage } from 'nap-typescript-sdk'; import { v4 as UUID } from 'uuid'; export class MyComponent { // proxy for SAMLAssertion public session$: Observable<NAPMessage | undefined> = this.napSDK.incoming$.pipe( filterEvents([NAPEventCatalogue.v1.SessionOpen, NAPEventCatalogue.v1.SessionClose]) ); //inject the nap-angular-sdk service constructor(private napSK: NapAngularService) { // Construct an SessionOpen NAPMessage const napMsg: NAPMessage = { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.SessionOpen }, }; // Ask for the SAMLassertion in host this.napSDK.sendMessage(napMsg); } /** * Tricker logout event */ logout(): void { const napMsg: NAPMessage = { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.SessionClose }, }; this.napSDK.sendMessage(napMsg); } } |
Følgende eksempel sender en patient-Open besked og får en patient tilbage.
import { NapAngularService } from 'nap-angular-sdk'; import { filterEvents, NAPEventCatalogue, NAPMessage, FHIRValueSetter, FHIRValueGetter } from 'nap-typescript-sdk'; import { v4 as UUID } from 'uuid'; export class MyComponent { // proxy for currentPatient public currentPatient$: Observable<NAPPatientInfo | undefined> = this.napSDK.incoming$.pipe( filterEvent(NAPEventCatalogue.v1.PatientOpen), map((message) => FHIRValueGetter.getPatientInfo(message)) ); //inject the nap-angular-sdk service constructor(private napSK: NapAngularService) { // Construct an patient NAPMessage const napMsg: NAPMessage = { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.PatientOpen} }; this.napSDK.sendMessage(napMsg); // Ask for the patient context in host this.napSDK.sendMessage(napMsg); } // Something triggered a patientClose on the client site public patientClose(patient: NAPPatientInfo) { const napMsg: NAPMessage = { date: new Date().toISOstring(), id: UUID(), event: { type: NAPEventType.PatientClose, context: [{ resource: { resourceType: FHIRValueSetter.FHIRResourceType.Patient, code: { coding: [{ code: NAPEventCatalogue.v1.Close, system: FHIRSystem.NAP}] }, identifier: [{ system: FHIRSystem.CPR, value: patient.ssNo, }], name: [{ family: patient.familyName, given: [patient.familyName] }], meta: {profile: ['http://hl7.dk/fhir/core/StructureDefinition/dk-core-patient']}, }], } }; // Send the message this.napSDK.sendMessage(napMsg); } } |
Hvis du ønsker at bruge React som udviklingsværktøj.
Da nap-react-sdk er en react specifik wrapper af nap-typescript-sdk, er der en peer dependency til samme version af dette SDK.
Nap-react-sdk udstiller en komponent kaldet NAPContextProvider. Denne komponent sørger for at kalde createNAP() fra nap-typescript-sdket og dermed initialisere kontekstbroen i React.UseEffect(), som kaldes efter render() kaldes første gang. Samtiditig subscribes der på de forskellige messagestreams, og deres emits håndteres i React.state på Contextprovideren. De forskellige subscriptions og håndtag håndteres i react.useCallback. De forskellige states og methode-håndtag pakkes alt sammen i en Context.
interface Context { latestIncoming: NAPMessage | null; latestError: NAPError | null; postMessage: (message: NAPMessage) => void; subscribe: (subscriber: NAPHostSubscriber) => void; unsubscribe: (subscriber: NAPHostSubscriber) => void; } |
Denne kontekst kan blive injectet i child elementer ved kalde `createNAP()`. Hvis denne funktion kaldes udenfor en NapContext kaster det en fejl.
Effekten for anvenderen bliver, at broen initialiseres som en singleton, og at beskeder sendt over broen opdatere context state af applikationen, og på den baggrund vil React kalder Render().
Følgende eksempel viser hvordan man kan anvende nap-react-sdk til at vise og sende beskeder:
import { NapContextProvider, NAPEventType, useNap } from 'nap-react-sdk'; import React from 'react'; import { v4 as UUID } from 'uuid'; const IncomingMessageComponent: React.FC = () => { const napContext = useNap() return <div> {JSON.stringify(napContext.latestIncoming)}</div> } const IncomingErrorsComponent: React.FC = () => { const napContext = useNap() return ( <div > <p> Error received: {JSON.stringify(napContext.latestError)}</p> </div> ) } const PostMessageComponent: React.FC = () => { const napContext = useNap() return ( <button onClick={() => { napContext.postMessage({ date: new Date().toString(), id: UUID(), event: { type: NAPEventType.SessionOpen } }) }} > Send message </button> ) } const App = () => { return ( <> <NapContextProvider> <IncomingMessageComponent></IncomingMessageComponent> <IncomingErrorsComponent></IncomingErrorsComponent> <PostMessageComponent></PostMessageComponent> </NapContextProvider> </> ) } export default App |
Generel kodedokumentation findes i bilblioteket.