Last active
January 28, 2021 19:16
-
-
Save AdamJLemmon/f91e366e04e9a708518d3528e0e8cae7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Dependencies | |
const axios = require('axios') | |
// Environment Variables | |
const API_URL = process.env.API_URL || 'https://api.dev.trybe.id' | |
const VCX_API_KEY = process.env.VCX_API_KEY || '42d34daf-29fc-4703-b52c-82c69f4e1a58' | |
const ORG_ID = process.env.ORG_ID || '60130d1fd955617015ece84b' | |
// API authZ | |
const orgId = ORG_ID | |
const headers = { | |
'vcx-api-key': VCX_API_KEY | |
} | |
// Credential data | |
// Patient - "required": ["resourceType", "extension", "identifier", "name", "gender", "birthDate"], | |
const Patient = { | |
resourceType: "Patient", | |
extension: [{ | |
url: "http://hl7.org/fhir/StructureDefinition/patient-nationality", | |
code: { "text": "SG" } | |
}], | |
identifier: [{ | |
type: { "text": "NRIC" }, | |
value: "S9098989Z" | |
}], | |
name: [{ | |
text: "Tan Chen Chen" | |
}], | |
gender: "female", | |
birthDate: "1990-01-15" | |
} | |
// Specimen - "required": ["resourceType", "type", "collection"], | |
const Specimen = { | |
resourceType: "Specimen", | |
type: { | |
coding: [{ | |
system: "http://snomed.info/sct", | |
code: "258500001", | |
display: "Nasopharyngeal swab" | |
}] | |
}, | |
collection: { | |
collectedDateTime: "2020-09-27T06:15:00Z" | |
} | |
} | |
// Observation - "required": [ "resourceType", "identifier", "code", "valueCodeableConcept", "effectiveDateTime", "qualification", "status" ], | |
const Observation = { | |
"resourceType": "Observation", | |
"identifier": [{ | |
"value": "123456789", | |
"type": "ACSN" | |
}], | |
"code": { | |
"coding": [{ | |
"system": "http://loinc.org", | |
"code": "94531-1", | |
"display": "Reverse transcription polymerase chain reaction (rRT-PCR) test" | |
}] | |
}, | |
"valueCodeableConcept": { | |
"coding": [{ | |
"system": "http://snomed.info/sct", | |
"code": "260385009", | |
"display": "Negative" | |
}] | |
}, | |
"effectiveDateTime": "2020-09-28T06:15:00Z", | |
"status": "final", | |
"performer": { | |
"name": [{ | |
"text": "Dr Michael Lim" | |
}] | |
}, | |
"qualification": [{ | |
"identifier": "MCR 123214", | |
"issuer": "MOH" | |
}] | |
} | |
// Organization - "required": ["resourceType", "name", "type", "contact"], | |
// Organization: Healtcare Provider | |
const Organization1 = { | |
"resourceType": "Organization", | |
"name": "MacRitchie Medical Clinic", | |
"type": "Licensed Healthcare Provider", | |
"contact": { | |
"telecom": [{ | |
"system": "phone", | |
"value": "+6563113111" | |
}], | |
"address": { | |
"type": "physical", | |
"use": "work", | |
"text": "MacRitchie Hospital Thomson Road Singapore 123000" | |
} | |
} | |
} | |
// Organization: Quest | |
const Organization2 = { | |
"resourceType": "Organization", | |
"name": "Quest Laboratories", | |
"type": "Accredited Laboratory", | |
"contact": { | |
"telecom": [{ | |
"system": "phone", | |
"value": "+6563113111" | |
}], | |
"address": { | |
"type": "physical", | |
"use": "work", | |
"text": "Quest Laboratories Address" | |
}, | |
} | |
} | |
// Package it all up into the credential | |
const credential = { | |
"type": [ "VerifiableCredential", "HealthPassportBundleCredentialV1" ], | |
credentialSubject: { | |
data: { | |
// "required": ["id", "name", "validFrom", "fhirVersion", "fhirBundle"] | |
'@type': 'BundleContainer', | |
id: 'Unique test ID', | |
name: 'HealthCert', | |
validFrom: new Date().toISOString(), | |
fhirVersion: '4.0.1', | |
fhirBundle: { | |
'@type': 'Bundle', | |
resourceType: 'Bundle', | |
type: 'collection', | |
entry: [ Patient, Specimen, Observation, Organization1, Organization2 ], | |
}, | |
}, | |
}, | |
} | |
/** | |
* Complete flow to issue a HealthCerts Verifiable Credential | |
*/ | |
const issueCredential = async ({ orgId, credential, options }) => { | |
const body = { credential, options, orgId } | |
const url = `${API_URL}/provider/issueCustomCredential` | |
const response = await axios.post(url, body, { headers }) | |
return response.data; | |
} | |
const run = async () => { | |
// Default response of wallet install and download URL no authN | |
let options = {} | |
let response = await issueCredential({ orgId, credential, options }) | |
console.log({ response1: response }) | |
// Default response of wallet install and download URL, user authN with passport number | |
options = { | |
requiredUserAuthentication: [{ | |
property: 'ppn', | |
acceptedValues: [ 'hn1234' ], | |
reason: "authentication", | |
description: 'Internaitonal Passport Number.', | |
reason: 'authentication' | |
}], | |
} | |
response = await issueCredential({ orgId, credential, options }) | |
console.log({ response2: response }) | |
// multiple response type including wallet install and download URL as well as qr code presentation URL, user authN with passport number | |
options = { | |
responseType: [ | |
'walletInstallAndCredentialDownloadUrl', | |
'encryptedCredentialPresentationUrl' | |
], | |
requiredUserAuthentication: [{ | |
property: 'ppn', | |
acceptedValues: [ 'hn1234' ], | |
reason: "authentication", | |
description: 'Internaitonal Passport Number.', | |
reason: 'authentication' | |
}], | |
} | |
response = await issueCredential({ orgId, credential, options }) | |
console.log({ response3: response }) | |
// greedy response type, returning the raw credential and URLs | |
options = { | |
responseType: [ | |
'credential', | |
'walletInstallAndCredentialDownloadUrl', | |
'encryptedCredentialPresentationUrl' | |
], | |
} | |
response = await issueCredential({ orgId, credential, options }) | |
console.log({ response4: response }) | |
// Raw QR code data, base64 data URI | |
options = { | |
responseType: 'encryptedCredentialPresentationQrCode', | |
} | |
response = await issueCredential({ orgId, credential, options }) | |
console.log({ response5: response }) | |
// download URL and QR code as well as presentation URL and QR code data | |
options = { | |
responseType: [ | |
'walletInstallAndCredentialDownloadUrl', | |
'walletInstallAndCredentialDownloadQrCode', | |
'encryptedCredentialPresentationUrl', | |
'encryptedCredentialPresentationQrCode', | |
] | |
} | |
response = await issueCredential({ orgId, credential, options }) | |
console.log({ response5: response }) | |
} | |
run() | |
// VCX_API_KEY=663b4151-2b80-4d46-80c2-c9ae3728a134 ORG_ID=5fc7d717da620b611af5de4f node apiProviderHealthCert.js |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment