Page History
Navitabs | ||||
---|---|---|---|---|
| ||||
Warning |
---|
NAP projektet er ikke aktivt og NAP er derfor ikke pt. under support og vedligehold. |
Table of Contents |
---|
Introduktion
Formål
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.
Sammenhæng med øvrige dokumenter
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 - InstallationsvejledningAnvendere af NAP sdk er primært gæstesystemudviklere, derfor er denne guide målrettet disse.
Nap-typescript-sdk
Nap-typescript-sdk indeholder et eventkatalog der definere de events der kan sender over NAP i en givende version
Følgende er et eksempel på at anvende eventkatalog version 1:
...
er det basale SDK. Det udstiller en række metoder og interfaces som bliver beskrevet nedenfor.
- Et NAP interface, som fungerer som en wrapper omkring NAP bridge (NAP SDK - Design og Arkitektur beskrivelse).
- Et NAP message interface, som er modellen for alle beskeder, som kan sendes over NAP. Disse beskeder er meget inspireret af FHIRcast.
- Et NAPEventCatalogue, der definerer events inspireret af FHIRCast
- Hjælpemetoder til at sende og formatere beskeder.
NAP interface
En wrapper af NAP Bridge, som et værtssystem ligger på global scope af den embeddede browser.
Code Block | ||
---|---|---|
| ||
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:
Code Block | ||
---|---|---|
| ||
import { createNAP, NAP} from "nap-typescript-sdk";
const nap:NAP = createNAP(); |
NAPMessage
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/).
Code Block | ||
---|---|---|
| ||
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;
valueString?: string;
valueBoolean?: boolean;
valueDate?: Date;
valueStringArray?: 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 foretaget en minimal implementation af FHIR for at kunne opfylde nedenstående eventkatalog.
NAPMassage Dataformat
Dataformaterne er inspireret af FHIRCast. I SDKet sker der tjek på at følgende felter opfylder dataformatet:
NapMessage Felt | |
---|---|
date | ISO 8601-2 timestamp eksempelvis: 2020-06-22T08:07:18.892Z |
id | UUID eksempelvis: 4ddabe25-5f7a-4bce-89c1-f017cf2bc569 |
I tilfældet af en besked ikke opfylder dataformatet sendes en fejlbesked på error$ (stream med error beskeder), som de indlejrede system kan lytte på.
Se nedenfor, hvordan denne error stream kan anvendes.
Eventkatalog
Dette eventkatalog lægger sig op af FHIR / FHIRcast. Der forekommer en naturlig udvidelse af FHIR / FHIRcast standarden i form af de events der kommunikerer selektion/retrieve/filtering af NAPProjekter.
Eventkatalog version 1 | |
NAPEventType | Funktionelle beskrivelse |
---|---|
WebAppSelected | Sendes udelukkende fra lobbyen. Anvendes når en bruger vælger en afprøvningsløsning i lobbyen |
ProjectsRetrieved | Sendes udelukkende fra lobbyen. Anvendes når projekter er hentet. Giver hosten en mulighed for at sortere i visning af projekter |
ProjectsFiltered | Anvendes udelukkende i Lobbyen. Anvendes til at filtrere i de projekter der vises. |
SessionClose | Hvis en bruger ønskes logget ud. Alt state skal slettes på web-applikationen. |
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. |
MessageFactory | Factory metoder til at kreere NAPMessages. createPatientOpenMessage: (uuid: string, givenName?: string[], familyName?: string, ssNo?: string) => NAPMessage, |
Som i FHIRCast definerer eventtypen dataformatet. Eksempler på disse events er illustreret nedenfor.
Dog er WebAppSelected, ProjectsRetrieved og ProjectsFiltered ikke beskrevet i dette dokument, da disse events er tilegnet kommunikation mellem lobby og værtssystem. Du kan finde mere information om disse events på NAP Platform - Guide til anvendere.
Eksempel på anvendelse af eventkatalog version 1:
Code Block | ||
---|---|---|
| ||
import { NAPEventCatalogue } from 'nap-typescript-sdk'; |
...
const sessionCloseEvent = NAPEventCatalogue.v1.SessionClose; |
NAPError
Interface for SDK fejl. Disse beskeder emittes af errors$ i tilfælde af initialiseringsfejl, hvis sker der fejl i createNAP() kaldet når NAP bridge skal wrappes, eller i tilfælde ar marshalling fejl, hvis en besked ikke overholder dataformatet. Se evt. NAPMessage Dataformat ovenfor.
Code Block | ||
---|---|---|
| ||
export interface NAPError {
id: number;
message: string;
isFatal: boolean;
}
|
Eksempel på brug af errors$
Fejl bliver således skrevet i web konsollen.
Code Block | ||
---|---|---|
| ||
this.napAngular.errors$.subscribe(res => {
console.error(res);
});
|
Eksemplet er taget fra NapRefWeb Referenceimplementering (NAP) - Leverancebeskrivelse.
Hjælpefunktioner
Nap-typescript-sdk indeholder derudover en række util-funktionerrække hjælpefunktioner, som kan være brugbare .
Følgende er et eksempel på anvendelse af mapping funktioner, der hiver data ud af nap-events.
til at hente værdier og generere NAPMessages.
Komplet liste over hjælpefunktioner:
Funktion | |
---|---|
nap-message-factory | |
createBasicNapMessage = (uuid: string, type: NAPEventType): NAPMessage | Laver en basal NAPMessage med det NAPEventType og ID som er angivet. Beskeden har ingen context. |
createPatientOpenMessageV1 = (uuid: string, givenName?: string[], familyName?: string, ssNo?: string): NAPMessage | Laver en patientOpen NAPMessage med de patientinformationer og det ID, som er angivet. |
createPatientCloseMessageV1 = (uuid: string, givenName?: string[], familyName?: string, ssNo?: string): NAPMessage | Laver en patientClose NAPMessage med de patientinformationer og det ID der er angivet. |
createSessionCloseMessageV1 = (uuid: string): NAPMessage | Laver en sessionClose NAPmessage med det ID der er angivet. |
createProjectsRetrievedMessageV1 = (uuid: string, webAppShortNames: string[]): NAPMessage | Anvendes kun i nap-lobby. Laver en NAPMessage med de Projekter, som er tilgængelig. |
createSessionErrorMessageV1 = (uuid: string, errorMessage: string, errorDescription: string): NAPMessage | Laver en sessionError NAPMessage med det ID og de fejl beskrivelser, som er angivet. |
createWebAppSelectedMessageV1 = ( | Anvendes kun i nap-lobby. Laver en WebAppSelectedNAPMessage med de WebApp detaljer der er angivet. |
FHIRValueGetter | |
getFilteredProjects(napMessage: NAPMessage): string[] | undefined | Anvendes kun i nap-lobby. Henter en filtreret liste af projekter der ønskes vist i lobbyen |
getPatientInfo(napMessage: NAPMessage): NAPPatientInfo | undefined | Henter patientinfo. Returnerer undefined, hvis ikke data kan formateres. |
filterEvents | |
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. |
Nap-Message-Factory
Funktioner der gør det lettere at generere NAPMessages.
Eksempel på anvendelse af message factory
Code Block | ||
---|---|---|
| ||
import { NAPEventCatalogue, NAPMessage } from 'nap-typescript-sdk';
import { v4 as UUID } from 'uuid';
const napMessageCurrentPatient = NAPEventCatalogue.v1.MessageFactory.createPatientOpenMessage(UUID())
const napMessageSessionClose = NAPEventCatalogue.v1.MessageFactory.createSessionCloseMessage(UUID());
const napMessageSessionError = NAPEventCatalogue.v1.MessageFactory.createSessionErrorMessage(UUID(), 'This is my error message', 'This is a longer description of the error message');
const napMessageRetrievedProjects = NAPEventCatalogue.v1.MessageFactory.createProjectsRetrievedMessage(UUID(), ['NAPTestWebShortName1', 'NAPTestWebShortName2', 'NAPTestWebShortName3', 'NAPTestWebShortName4', 'NAPTestWebShortName5', 'NAPTestWebShortName6']);
const napMessagewebAppSelected = NAPEventCatalogue.v1.MessageFactory.createWebAppSelectedMessage(UUID(), 'webAppUrl', 'webAppProducer', new Date(Date.now()), 'webAppShortName', 'webAppServiceEntry', ['1'])
|
FHIR-Value-getter
Funktioner, som gør det lettere at hente FHIR specifikke værdier ud af en NAPMessage. Disse kan bruges ved at importere namespacet FHIRValueGetter.
Eksempel på anvendelse af FHIR-value-setter
Følgende eksempel mapper en NAPMessage til PatientInfo.
Code Block | ||
---|---|---|
| ||
import { FHIRValueGetter, NAPMessage, NAPPatientInfo } from 'nap-typescript-sdk';
const patientData: NAPPatientInfo = FHIRValueGetter.getSessionValue(napMessage); |
filterEvent
Funktion, som gør det lettere at sortere i eventstrømmen og dermed subscribe til specifikke event typer
Eksempel på anvendelse af filterEvent
Code Block | ||
---|---|---|
| ||
import {filterEvents, NAPEventCatalogue} from 'nap-typescript-sdk';
nap.incoming$.pipe(
filterEvent(
NAPEventCatalogue.v1.SessionClose,
)
) |
Fhir-Value-Setter
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 |
FHIRExtensionURL.WEBAPPSHORTNAMES |
FHIRExtensionURL.WEBAPPSHORTNAME |
FHIRExtensionURL.WEBAPPAUDIENCE |
FHIRExtensionURL.WEBAPPSERVICEENTRY |
FHIRExtensionURL.WEBAPPPRODUCER |
FHIRExtensionURL.WEBAPPRELEASEDATE |
FHIRExtensionURL.WEBAPPURL |
FHIRExtensionURL.WEBAPPCATALOGUEVERSIONS |
Eksempel på anvendelse Fhir-Value-Setter (Session Error)
Følgende er et eksempel hvordan der sendes en fejlbesked.
Code Block | ||
---|---|---|
| ||
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) |
Nap-angular-sdk
Hvis du ønsker at bruge Angular som udviklingsværktøj.
...
Da nap-angular-sdk er en angular specifik wrapper af nap-typescript-sdk har den , 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 . Et eksempel for implementing 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.
Code Block | ||
---|---|---|
| ||
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.
Eksempel på anvendelse af nap-angular-sdk
...
Generel kodedokumentation findes i biblioteket. Fuld implementation af eventkataloget ses i nap-reference-web her https://svn.nspop.dk/src/components/nap/nap-reference-web/trunk/.
Session-close
Følgende eksempel sender / modtager en Session-Close besked når ønsker, at blive logget ud.
Code Block | ||
---|---|---|
| ||
import { NapAngularService } from |
...
'nap-angular-sdk'; |
...
import { |
...
filterEvent, NAPEventCatalogue, NAPMessage } from 'nap-typescript-sdk'; |
...
import { v4 as UUID } from 'uuid'; export class MyComponent { innerLogout = new Subject<undefined>(); logOut$: Observable<undefined> = merge( this.innerLogout, this.napSDK.incoming$.pipe( filterEvent(NAPEventCatalogue.v1.SessionClose), map(() => undefined)), ); //inject the nap-angular-sdk service constructor(private napSK: NapAngularService) { } /** * Handle logout events */ logout(): void { const napMsg: NAPMessage = { date: new Date().toISOString(), id: UUID(), event: { type: NAPEventCatalogue.v1.SessionClose }, }; this.napSDK.sendMessage(napMsg); this.innerLogout.next(undefined); } } |
Patient-Open og Patient-close
Følgende eksempel sender en patient-Open besked og får en patient tilbage.
Code Block | ||
---|---|---|
| ||
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); |
...
} } |
Nap-react-sdk
Hvis du ønsker at bruge React som udviklingsværktøj.
Da nap-react-sdk er en react specifik wrapper af nap-typescript-sdk har den en peer dependency til , 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 . Et eksempel for implementing 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 metode-håndtag pakkes alt sammen i en Context.
Code Block | ||
---|---|---|
| ||
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 kastes 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().
Eksempel på anvendelse af nap-react-sdk SessionClose og latestError
Følgende eksempel viser hvordan man kan anvende nap-react-sdk til at få vise og sende beskeder kunne se således ud:
Code Block | ||
---|---|---|
| ||
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.SessionClose } }) }} > Send message </button> ) } const App = () => { return ( <> <NapContextProvider> <IncomingMessageComponent></IncomingMessageComponent> <IncomingErrorsComponent></IncomingErrorsComponent> <PostMessageComponent></PostMessageComponent> </NapContextProvider> </> ) } export default App |
Generel kodedokumentation findes i biblioteket.SessionOpen }
})
}}
>
Send message
</button>
)
}
constApp = () => {
return (
<>
<NapContextProvider>
<IncommingMessageComponent></IncommingMessageComponent>
<PostMessageComponent></PostMessageComponent>
</NapContextProvider>
</>
)
}
exportdefaultApp