-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.ts
More file actions
132 lines (114 loc) · 4.62 KB
/
index.ts
File metadata and controls
132 lines (114 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import express, {Request, Response} from "express";
import {AuthorizationToken, BlueButton} from "cms-bluebutton-sdk";
import * as fs from "fs";
interface User {
authToken?: AuthorizationToken,
eobData?: any,
errors?: string[]
}
const BENE_DENIED_ACCESS = "access_denied"
const FE_MSG_ACCESS_DENIED = "Beneficiary denied app access to their data"
const ERR_QUERY_EOB = "Error when querying the patient's EOB!"
const ERR_MISSING_AUTH_CODE = "Response was missing access code!"
const ERR_MISSING_STATE = "State is required when using PKCE"
const app = express();
const bb = new BlueButton();
const authData = bb.generateAuthData();
// This is where medicare.gov beneficiary associated
// with the current logged in app user,
// in real app, this could be the app specific
// account management system
const loggedInUser: User = {
};
// helper to clean up cached eob data
function clearBB2Data() {
loggedInUser.authToken = undefined;
loggedInUser.eobData = {};
}
// AuthorizationToken holds access grant info:
// access token, expire in, expire at, token type, scope, refreh token, etc.
// it is associated with current logged in user in real app,
// check SDK js docs for more details.
let authToken: AuthorizationToken;
// auth flow: response with URL to redirect to Medicare.gov beneficiary login
app.get("/api/authorize/authurl", (req: Request, res: Response) => {
res.send(bb.generateAuthorizeUrl(authData));
});
// auth flow: oauth2 call back
app.get("/api/bluebutton/callback", (req: Request, res: Response) => {
(async (req: Request, res: Response) => {
if (typeof req.query.error === "string") {
// clear all cached claims eob data since the bene has denied access
// for the application
clearBB2Data();
let errMsg = req.query.error;
if (req.query.error === BENE_DENIED_ACCESS) {
errMsg = FE_MSG_ACCESS_DENIED;
}
loggedInUser.eobData = {"message": errMsg};
process.stdout.write(errMsg + '\n');
} else {
if (
typeof req.query.code === "string" &&
typeof req.query.state === "string"
) {
try {
authToken = await bb.getAuthorizationToken(
authData,
req.query.code,
req.query.state
);
// data flow: after access granted
// the app logic can fetch the beneficiary's data in app specific ways:
// e.g. download EOB periodically etc.
// access token can expire, SDK automatically refresh access token when that happens.
const eobResults = await bb.getExplanationOfBenefitData(authToken);
authToken = eobResults.token; // in case authToken got refreshed during fhir call
loggedInUser.authToken = authToken;
loggedInUser.eobData = eobResults.response?.data;
} catch (e) {
loggedInUser.eobData = {};
process.stdout.write(ERR_QUERY_EOB + '\n');
process.stdout.write("Exception: " + e + '\n');
}
} else {
clearBB2Data();
process.stdout.write(ERR_MISSING_AUTH_CODE + '\n');
process.stdout.write("OR" + '\n');
process.stdout.write(ERR_MISSING_STATE + '\n');
process.stdout.write("AUTH CODE: " + req.query.code + '\n');
process.stdout.write("STATE: " + req.query.state + '\n');
}
}
const fe_redirect_url =
process.env.SELENIUM_TESTS ? 'http://client:3000' : 'http://localhost:3000';
res.redirect(fe_redirect_url);
}
)(req, res);
});
app.get("/api/bluebutton/loadDefaults", (req: Request, res: Response) => {
loggedInUser.eobData = loadDataFile("Dataset 1", "eobData");
res.send(process.env.SELENIUM_TESTS ? 'http://client:3000' : 'http://localhost:3000');
});
// helper to load json data from file
function loadDataFile(dataset_name: string, resource_file_name: string): any {
const filename = `./default_datasets/${dataset_name}/${resource_file_name}.json`
const resource = fs.readFileSync(filename, 'utf-8')
try {
return JSON.parse(resource);
} catch (error) {
process.stdout.write("Error parsing JSON: " + error);
return null
}
}
// data flow: front end fetch eob
app.get("/api/data/benefit", (req: Request, res: Response) => {
if (loggedInUser.eobData) {
res.json(loggedInUser.eobData);
}
});
const port = 3001;
app.listen(port, () => {
process.stdout.write(`[server]: Server is running at https://localhost:${port}`);
process.stdout.write("\n");
});