How to do Fhir? - node.js

I'm trying to learn the basics of fhir and want to implement in node js.
I have come across the following code https://github.com/FHIR/fhir.js
In that it says that i have to create a instance of FHIR client?
I know my question is dumb, so can i get any clarifications on the topic.
I have started learning node a few days back.
Thanks in advance!
var config = {
// FHIR server base url
baseUrl: 'http://myfhirserver.com',
auth: {
bearer: 'token',
// OR for basic auth
user: 'user',
pass: 'secret'
},
// Valid Options are 'same-origin', 'include'
credentials: 'same-origin',
headers: {
'X-Custom-Header': 'Custom Value',
'X-Another-Custom': 'Another Value',
}
}
myClient = fhir(config, adapter)
Above is the code for creating an instance of Fhir client, I want to know where should i implement this code and access a fhir server.

From the README, for use with Node:
var mkFhir = require('fhir.js');
var client = mkFhir({
baseUrl: 'http://try-fhirplace.hospital-systems.com'
});
client
.search( {type: 'Patient', query: { 'birthdate': '1974' }})
.then(function(res){
var bundle = res.data;
var count = (bundle.entry && bundle.entry.length) || 0;
console.log("# Patients born in 1974: ", count);
})
.catch(function(res){
// Error responses
if (res.status){
console.log('Error', res.status);
}
// Errors
if (res.message){
console.log('Error', res.message);
}
});

I would recommend using one of the publicly available FHIR test servers as outlined here: http://wiki.hl7.org/index.php?title=Publicly_Available_FHIR_Servers_for_testing
It seems as though you are generating a client for communicating with the FHIR server but you would need to update the base URL in the third line of your code.

FHIR WITH NODEJS
First we need to fetch the access Token
After fetching the token we can easily create the Patient record just by passing the values via POSTMAN as req.body and than it will manipulate the request data into FHIR.
We can fetch the Patient record as per our response body.
All three services are coded below:
const CLIENT_ID = FHIR_CLIENT_ID;
const APP_SECRET = FHIR_CLIENT_SECRET;
const { BASE, RESOURCE } = fhir;
const instance = axios.create({
baseURL: RESOURCE,
});
const getAccessToken = async () => {
const response = await axios({
url: `${BASE}/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/oauth2/token`,
method: 'post',
data: `grant_type=Client_Credentials&resource=${RESOURCE}`,
auth: {
username: CLIENT_ID,
password: APP_SECRET,
},
});
return response.data.access_token;
};
const createPatient = async (patientBody) => {
const {
firstName,
middleIniital,
lastName,
birthDate,
gender,
reference,
address,
city,
state,
zipcode,
email,
phone,
ssn,
mrn,
} = patientBody;
const newFhirPatient = {
resourceType: 'Patient',
name: [
{ text: 'First Name', given: [firstName] },
{ text: 'Middle Name', given: [middleIniital] },
{ text: 'Last Name', given: [lastName] },
],
birthDate,
gender,
managingOrganization: { type: 'Organization', reference },
address: [{ text: address, city, state, postalCode: zipcode }],
contact: [
{
telecom: [
{ system: 'email', value: email },
{ system: 'phone', value: phone },
],
relationship: {
coding: [
{ display: 'SSN', code: ssn },
{ display: 'MRN', code: mrn },
],
},
},
],
};
const accessToken = await getAccessToken();
try {
const response = await instance.post('/Patient', newFhirPatient, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return response.data;
} catch (error) {
throw error;
}
};
const getPatient = async () => {
const accessToken = await getAccessToken();
try {
const response = await instance.get('/Patient', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
const data = [];
for (let i = 0; i < response.data.entry.length; i++) {
const entry = response.data.entry[i];
var id = (entry.resource.id !== undefined) ? entry.resource.id : "";
var firstName = (entry.resource.name?.[0]?.given?.[0] !== undefined) ? entry.resource.name?.[0]?.given?.[0] : "";
var middleName = (entry.resource.name?.[1]?.given?.[0] !== undefined) ? entry.resource.name?.[1]?.given?.[0] : "";
var lastName = (entry.resource.name?.[2]?.given?.[0] !== undefined) ? entry.resource.name?.[2]?.given?.[0] : "";
var birthDate = (entry.resource.birthDate !== undefined) ? entry.resource.birthDate : "";
var gender = (entry.resource.gender !== undefined) ? entry.resource.gender : "";
var address = (entry.resource.address?.[0]?.text !== undefined) ? entry.resource.address?.[0]?.text : "";
var city = (entry.resource.address?.[0]?.city !== undefined) ? entry.resource.address?.[0]?.city : "";
var state = (entry.resource.address?.[0]?.state !== undefined) ? entry.resource.address?.[0]?.state : "";
var zipcode = (entry.resource.address?.[0]?.zipcode !== undefined) ? entry.resource.address?.[0]?.zipcode : "";
var ssn = (entry.resource.contact?.[0]?.relationship?.[0]?.coding?.[0].code !== undefined) ? entry.resource.contact?.[0]?.relationship?.[0]?.coding?.[0].code : "";
var mrn = (entry.resource.contact?.[0]?.relationship?.[0]?.coding?.[1].code !== undefined) ? entry.resource.contact?.[0]?.relationship?.[0]?.coding?.[1].code : "";
var email = (entry.resource.contact?.[0]?.telecom?.[0]?.value !== undefined) ? entry.resource.contact?.[0]?.telecom?.[0]?.value : "";
var phone = (entry.resource.contact?.[0]?.telecom?.[1]?.value !== undefined) ? entry.resource.contact?.[0]?.telecom?.[1]?.value : "";
var organizationId = (entry.resource.managingOrganization?.reference !== undefined) ? entry.resource.managingOrganization?.reference : "";
data.push({
id,
firstName,
middleName,
lastName,
birthDate,
gender,
address,
city,
state,
zipcode,
email,
phone,
ssn,
mrn,
organizationId,
});
}
return data;
} catch (error) {
throw error;
}
};
After getting the access Token you can create the Patient like this in NodeJS
and send the data into FHIR in their manner
const createPatient = async (patientBody) => {
const {
firstName,
middleIniital,
lastName,
birthDate,
gender,
reference,
address,
city,
state,
zipcode,
email,
phone,
ssn,
mrn,
} = patientBody;
const newFhirPatient = {
resourceType: 'Patient',
name: [
{ text: 'First Name', given: [firstName] },
{ text: 'Middle Name', given: [middleIniital] },
{ text: 'Last Name', given: [lastName] },
],
birthDate,
gender,
managingOrganization: { type: 'Organization', reference },
address: [{ text: address, city, state, postalCode: zipcode }],
contact: [
{
telecom: [
{ system: 'email', value: email },
{ system: 'phone', value: phone },
],
relationship: {
coding: [
{ display: 'SSN', code: ssn },
{ display: 'MRN', code: mrn },
],
},
},
],
};
const accessToken = await getAccessToken();
try {
const response = await instance.post('/Patient', newFhirPatient, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
return response.data;
} catch (error) {
throw error;
}
};

Related

Razorpay not returning payment_id,order_id etc. upon successfull payment

I have one function that is responsible of creating order using razorpay and verify that order .
The code for that function is : -
const paymentMethod = async ()=>{
if(!isAuthenticated())
{
toast.error('Please signin to continue');
history.push('/signin')
// return <Redirect to='/signin' />
return;
}
try{
// console.log(JSON.stringify(total));
const obj = {
amount:total
}
let data = await fetch('http://localhost:3100/api/checkout',{
method:'POST',
headers:{
"content-type":"application/json",
Accept:"application/json"
},
body: JSON.stringify(obj)
})
let {order} = await data.json()
console.log(order)
console.log(order.amount)
const options = {
key: "rzp_test_cXj3ybg8fawS9Y",
amount: order.amount,
currency: "INR",
name: "YO! Merchandise",
description: "Pay Please",
image:yo,
order_id: order.id,
callback_url: "http://localhost:3100/api/paymentverification",
prefill: {
name: "Aakash Tiwari",
email: "tiwaryaakash00#gmail.com",
contact: "8750043604"
},
notes: {
address: "Razorpay Corporate Office"
},
theme: {
color: "#13C962"
}
};
let rzp1 = await new window.Razorpay(options);
rzp1.open();
}
catch(err){
console.log(err)
}
}
But this function when call callback_url upon successfull payment it is not passing the payment_id,order_id etc. other neccessary details.
when i try to console.log there the req.body is always empty.

createAysncThunk in Redux Toolkit catching error when making fetch request

I'm working on the user registration functionality of an application using Typescript and Redux Toolkit. When I make the fetch request to the signup endpoint, a new user is saved to the database I've connected, but I keep entering the catch error block.
export const registerUser = createAsyncThunk(
"user/registerUser",
async (form: { username:string, password:string }, thunkAPI) => {
try {
const response = await fetch('/api/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userInfo: {
username: form.username,
password: form.password
}
}),
});
if (response.status === 200) return 200;
else return 400;
} catch (e) {
console.log('Error')
}
}
);
I've tried logging the response to the console a number of ways
const data = await response.json() console.log(data)
But have had no luck. I think this is an error with how I've done my fetch request using createAsyncThunk but haven't been able to figure out what I've missed.
This is the code for the initial state and slice:
interface UserState {
userProfile: {
id: number | null;
},
registration: {
status: 'loaded' | 'loading'
}
}
const initialState : UserState = {
userProfile: {
id: null,
},
registration: {
status: 'loaded'
}
};
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
},
extraReducers: (builder) => {
builder.addCase(registerUser.fulfilled, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.rejected, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.pending, (state) => { state.registration.status = 'loading' })
}
})
And here is the code for the function where the action is dispatched on the UI
const handleRegister= async () => {
if (!username) return alert('Username field was left empty');
if (!password) return alert('Password field was left empty');
const {payload} : any = await dispatch(registerUser({ username: username, password: password}));
if (payload === 200) {
alert('Successfully registered. Redirecting to dashboard');
return navigate('/dashboard');
} else { return alert('User creation unsuccessful'); }
}
Appreciate any help as I've looked through many other posts but haven't been able to resolve my issue.

file writing function working on localhost but not on azure

I have a function in my node js app that takes information and creates a csv file, then uploads it to the server. The code is below:
//check user has enough credits
if (req.user.credits >= 5) {
//check if user selected a recipient, and handle
let { name, address, state, country, city, postcode, message, note_name } = "";
let createRecipient = true;
if (req.body.recipient != "none") {
createRecipient = false
const recipient = await userController.getRecipientById(req.body.recipient);
name = recipient.name
address = recipient.address
state = recipient.state
country = recipient.country
city = recipient.city
postcode = recipient.postcode
message = req.body.message
note_name = req.body.note_name
} else {
name = req.body.name
address = req.body.address
state = req.body.state
country = req.body.country
city = req.body.city
postcode = req.body.postcode
message = req.body.message
note_name = req.body.note_name
}
const path = 'uploads\\notes_files\\';
const filename = path + randomUUID() + '.csv';
//first, save recipent to database
console.log(createRecipient + req.body.save_recipient)
if (createRecipient && req.body.save_recipient == 'on') {
db.query('INSERT into RECIPIENTS SET ?', {user_id: req.user.id, name: name, address: address, state: state, country: country, city: city, postcode: postcode }, function(err) {
if (err) throw err
});
}
//next, create a CSV file
const csvWriter = createCsvWriter({
path: filename,
header: [
{id: 'name', title: 'Name'},
{id: 'address', title: 'Address'},
{id: 'state', title: 'State'},
{id: 'country', title: 'Country'},
{id: 'city', title: 'City'},
{id: 'postcode', title: 'Postcode'},
{id: 'message', title: 'Message'}
]
});
const records = [
{name: name, address: address, state: state, country: country, city: city, postcode: postcode, message: message}
];
await csvWriter.writeRecords(records)
.then(() => {
let note_id;
db.query(`INSERT INTO notes SET ?`, {filename: 'temp', user_id: req.user.id, note_status: 'pending', note_name: note_name }, function(err, result) {
if (err) throw err;
// rename file to format 'note*id*_user*id*
note_id = result.insertId
const new_filename = 'note' + note_id + '_user' + req.user.id + '.csv'
//update in DB
db.query('UPDATE notes SET filename = ? WHERE note_id = ?', [ new_filename, note_id ], function(err) {
if (err) throw err;
//move to uploads folder
fs.rename(filename, path + new_filename, function(err) {
if (err) {
console.log(err);
res.send('There was a problem uploading your file. Please try again.');
}
//create notification before ending function
userController.createNotification(req.user.id, "New Note", "New note has been sent to our team for approval.");
res.redirect('/');
});
});
});
})
} else {
res.status(400).send('Not enough credits.')
}
}
this works fine on localhost, but when i deploy the app on an azure web app, i get this error in the azure logs:
2022-06-07T06:33:57.961918438Z node:internal/process/promises:246
2022-06-07T06:33:57.961969838Z triggerUncaughtException(err, true /* fromPromise */);
2022-06-07T06:33:57.961997638Z ^
2022-06-07T06:33:57.962012639Z
2022-06-07T06:33:57.962016639Z [Error: EINVAL: invalid argument, open 'uploads\notes_files\1d624787-2d06-41d7-909e-bb6283ea0efb.csv'] {
2022-06-07T06:33:57.962020839Z errno: -22,
2022-06-07T06:33:57.962024839Z code: 'EINVAL',
2022-06-07T06:33:57.962028639Z syscall: 'open',
2022-06-07T06:33:57.962102239Z path: 'uploads\\notes_files\\1d624787-2d06-41d7-909e-bb6283ea0efb.csv'
2022-06-07T06:33:57.962110639Z }
Any clue as to why this is working on localhost but not on azure?

custom user controller method not being called by strapi

So i'm building a site backend for a project using strapi. A requirement for the site backend is there has to be a e-commerce component included since the client wants to do order processing, and process credit card transactions using stripe. With the that being said I decided to write a custom controller for user accounts that are created under the user-permissions plugin for strapi. This way I could link the user accounts from strapi to corresponding customer accounts on stripe's end.
However, i'm running into one problem in particular. The custom user controller methods I have written for creating and updating users seem to work as intended. Though whenever I delete users strapi doesn't seem to use the custom method I have written for deleting users at all. I even included a console.log call but nothing pops up.
I'm not really sure on how to go about fixing this issue since I can't see any of the log calls, and strapi doesn't seem to be spitting out any errors either when this occurs. Any advice on how to go about resolving this issue is appreciated.
Here's the custom controller i'm working on.
<project_dir>/extensions/user-permissions/controllers/User.js
'use strict';
/**
* A set of functions called "actions" for `user`
*/
const _ = require('lodash'),
{ sanitizeEntity } = require('strapi-utils'),
stripe = require('stripe')('<SK_HERE>'),
sanitizeUser = (user) => sanitizeEntity(user, {model: strapi.query('user', 'users-permissions').model}),
formatError = (error) => [{ messages: [{ id: error.id, message: error.message, field: error.field }] }];
module.exports = {
async create(ctx) {
const advanced = await strapi.store({
environment: '',
type: 'plugin',
name: 'users-permissions',
key: 'advanced'
}).get();
const { email, username, firstName, lastName, password, role } = ctx.request.body;
if (!email) return ctx.badRequest('missing.email');
if (!username) return ctx.badRequest('missing.username');
if (!password) return ctx.badRequest('missing.password');
if (!firstName) return ctx.badRequest('missing.firstName');
if (!lastName) return ctx.badRequest('missing.lastName');
const userWithSameUsername = await strapi
.query('user', 'users-permissions')
.findOne({ username });
if (userWithSameUsername) {
return ctx.badRequest(
null,
formatError({
id: 'Auth.form.error.username.taken',
message: 'Username already taken.',
field: ['username'],
})
);
}
if (advanced.unique_email) {
const userWithSameEmail = await strapi
.query('user', 'users-permissions')
.findOne({ email: email.toLowerCase() });
if (userWithSameEmail) {
return ctx.badRequest(
null,
formatError({
id: 'Auth.form.error.email.taken',
message: 'Email already taken.',
field: ['email'],
})
);
}
}
const user = {
...ctx.request.body,
provider: 'local',
};
user.email = user.email.toLowerCase();
if (!role) {
const defaultRole = await strapi
.query('role', 'users-permissions')
.findOne({ type: advanced.default_role }, []);
user.role = defaultRole.id;
}
try {
const customer = await stripe.customers.create({name: `${firstName} ${lastName}`, email: email});
user.stripeId = customer.id;
const data = await strapi.plugins['users-permissions'].services.user.add(user);
ctx.created(sanitizeUser(data));
} catch (error) {
ctx.badRequest(null, formatError(error));
}
},
async update(ctx) {
const advancedConfigs = await strapi.store({
environment: '',
type: 'plugin',
name: 'users-permissions',
key: 'advanced',
}).get();
const { id } = ctx.params;
const { email, username, password, firstName, lastName} = ctx.request.body;
const user = await strapi.plugins['users-permissions'].services.user.fetch({id});
if (_.has(ctx.request.body, 'email') && !email) {
return ctx.badRequest('email.notNull');
}
if (_.has(ctx.request.body, 'username') && !username) {
return ctx.badRequest('username.notNull');
}
if (_.has(ctx.request.body, 'firstName') && !firstName) {
return ctx.badRequest('firstName.notNull');
}
if (_.has(ctx.request.body, 'lastName') && !lastName) {
return ctx.badRequest('lastName.notNull');
}
if (_.has(ctx.request.body, 'password') && !password && user.provider === 'local') {
return ctx.badRequest('password.notNull');
}
if (_.has(ctx.request.body, 'username')) {
const userWithSameUsername = await strapi
.query('user', 'users-permissions')
.findOne({ username });
if (userWithSameUsername && userWithSameUsername.id != id) {
return ctx.badRequest(
null,
formatError({
id: 'Auth.form.error.username.taken',
message: 'username.alreadyTaken.',
field: ['username'],
})
);
}
}
if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
const userWithSameEmail = await strapi
.query('user', 'users-permissions')
.findOne({ email: email.toLowerCase() });
if (userWithSameEmail && userWithSameEmail.id != id) {
return ctx.badRequest(
null,
formatError({
id: 'Auth.form.error.email.taken',
message: 'Email already taken',
field: ['email'],
})
);
}
ctx.request.body.email = ctx.request.body.email.toLowerCase();
}
let updateData = {
...ctx.request.body,
};
if (_.has(ctx.request.body, 'password') && password === user.password) {
delete updateData.password;
}
if(email != null || firstName != null || lastName != null) {
let stripeUpdate = {};
if(email != null && (email !== user.email)) stripeUpdate = {...stripeUpdate, email: email};
if((firstName != null && (firstName !== user.firstName)) || (lastName != null && (lastName !== user.lastName))) stripeUpdate = {
...stripeUpdate,
name: `${firstName != null && (firstName !== user.firstName) ? firstName : user.firstName} ${lastName != null && (lastName !== user.lastName) ? lastName : user.lastName}`
};
if(Object.keys(stripeUpdate).length > 0) {
const customerUpdate = await stripe.customers.update(user.stripeId, stripeUpdate);
}
}
const data = await strapi.plugins['users-permissions'].services.user.edit({ id }, updateData);
ctx.send(sanitizeUser(data));
},
async destroy(ctx) {
console.log('test...');
const { id } = ctx.params,
user = await strapi.plugins['users-permissions'].services.user.fetch({id}),
customerDelete = await stripe.customers.del(user.stripeId),
data = await strapi.plugins['users-permissions'].services.user.remove({id});
ctx.send(sanitizeUser(data));
}
};
Did you activate the destroy action in user-permissions?
I've tested it with this simple User.js in <project_dir>/extensions/user-permissions/controllers/:
module.exports = {
async find(ctx) {
console.log('find!!!');
return [];
},
async destroy(ctx) {
console.log('destroy!!!');
return [];
},
}
console.log('destroy!!!') is called when I send a DELETE request to http://localhost:1337/users/1234

Push notification returns ECONNRESET in Google Cloud Functions

I am having a function in Firebase Cloud Functions that is retrieves the user's device group id in order to send a push notification, and after sends a push notification. This works well if the function gets called only once, but if I have an array of users I want to send a push notification too, the sendPushNotification function returns error : FAILED err= { RequestError: Error: read ECONNRESET
at new RequestError (/user_code/node_modules/request-promise/node_modules/request-promise-core/lib/errors.js:14:15) for every try to send push
From what i understand ECONNRESET means that the connection gets closed at one end before finishing the operation, can some help/explain me why this is:
here is my code:
function sendFollowNotification(snapshot) {
const notificationMsg = getFollowNotificationMsg() //returns a string
snapshot.forEach(function(singleUser, index) {
const userId = singleUser.key;
const userObject = singleUser.val();
console.log("will get device group")
if (index + 1 == snapshot.numChildren()) {
return getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", true);
} else {
getDeviceGroupNotificationKey(userId, "Discover new artists", notificationMsg, "", false);
}
}
function getDeviceGroupNotificationKey(groupId, notificationTitle, notificationBody, notificationSubject, shouldReturn) {
const pathToDeviceGroup = admin.database().ref('deviceGroups').child(groupId);
pathToDeviceGroup.once("value").then( function(snapshot) {
const deviceGroupObj = snapshot.val();
const notification_key = deviceGroupObj.notification_key;
console.log("got notification key")
console.log(notification_key)
if (notification_key !== undefined) {
return sendPushToDeviceGroupOld(notification_key, notificationTitle, notificationBody, "notificationKeyOld2", notificationSubject, shouldReturn);
} else {
return
}
}).catch(reason => {
console.log("user device group not there")
return
})
}
function sendPushToDeviceGroupOld(notification_key, title, body, subject, message, shouldReturn) {
console.log('sending push to ' + notification_key)
const serverKey = '-';
const senderId = '-';
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
'project_id': senderId
},
body: {
to: notification_key,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
sound: "default",
},
priority : 'high',
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
return
})
.catch((err) => {
console.log('FAILED', err);
return
});
}

Resources