Compare commits
6 Commits
3287b9cde9
...
49c0485f96
| Author | SHA1 | Date | |
|---|---|---|---|
| 49c0485f96 | |||
| f23311636f | |||
| 7e32c570a1 | |||
| a40f5744c9 | |||
| a7cce12679 | |||
| 9be8780edf |
@ -6,7 +6,6 @@ var logger = require('morgan');
|
|||||||
|
|
||||||
var iti65Router = require('./routes/iti65');
|
var iti65Router = require('./routes/iti65');
|
||||||
var iti67Router = require('./routes/iti67');
|
var iti67Router = require('./routes/iti67');
|
||||||
var iti68Router = require('./routes/iti68');
|
|
||||||
var iti78Router = require('./routes/iti78');
|
var iti78Router = require('./routes/iti78');
|
||||||
var iti104Router = require('./routes/iti104');
|
var iti104Router = require('./routes/iti104');
|
||||||
var vhlRouter = require('./routes/vhl');
|
var vhlRouter = require('./routes/vhl');
|
||||||
@ -16,16 +15,14 @@ var app = express();
|
|||||||
app.use(logger('dev'));
|
app.use(logger('dev'));
|
||||||
app.use(express.json({ type: ['application/json', 'application/fhir+json'] }));
|
app.use(express.json({ type: ['application/json', 'application/fhir+json'] }));
|
||||||
|
|
||||||
// ITI-65: Provide Document Bundle → POST /fhir
|
// ITI-65: Provide Document Bundle → POST /fhir/IPSTransaction (transaction Bundle)
|
||||||
|
// POST /fhir/IPSDocument (IPS document Bundle)
|
||||||
app.use('/fhir', iti65Router);
|
app.use('/fhir', iti65Router);
|
||||||
|
|
||||||
// ITI-67: Find Document References → GET /fhir/DocumentReference
|
// ITI-67: Find Document References → GET /fhir/DocumentReference
|
||||||
app.use('/fhir', iti67Router);
|
app.use('/fhir', iti67Router);
|
||||||
|
|
||||||
// ITI-68: Retrieve Document → GET /fhir/Binary?url=[URL_Directa]
|
// ITI-78: Patient Demographics → GET /fhir/Patient, GET /fhir/Patient/:id
|
||||||
app.use('/fhir', iti68Router);
|
|
||||||
|
|
||||||
// ITI-78: Patient Demographics → GET /fhir/Patient[/:id]
|
|
||||||
app.use('/fhir', iti78Router);
|
app.use('/fhir', iti78Router);
|
||||||
|
|
||||||
// ITI-104: Patient Identity Feed → POST /fhir/Patient, PUT /fhir/Patient/:id
|
// ITI-104: Patient Identity Feed → POST /fhir/Patient, PUT /fhir/Patient/:id
|
||||||
@ -58,6 +55,15 @@ app.use(function (req, res, next) {
|
|||||||
|
|
||||||
// Error handler
|
// Error handler
|
||||||
app.use(function (err, req, res, _next) {
|
app.use(function (err, req, res, _next) {
|
||||||
|
// Error proveniente de HAPI FHIR o del Bus: reenviar la respuesta tal como llegó
|
||||||
|
if (err.response) {
|
||||||
|
const status = err.response.status;
|
||||||
|
console.warn(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} -> ${status} (upstream)`);
|
||||||
|
const contentType = err.response.headers?.['content-type'];
|
||||||
|
if (contentType) res.setHeader('Content-Type', contentType);
|
||||||
|
return res.status(status).json(err.response.data);
|
||||||
|
}
|
||||||
|
|
||||||
const status = err.status || 500;
|
const status = err.status || 500;
|
||||||
if (status >= 500) {
|
if (status >= 500) {
|
||||||
console.error(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} -> ${status}`, err);
|
console.error(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl} -> ${status}`, err);
|
||||||
|
|||||||
@ -1,90 +1,68 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/**
|
|
||||||
* Module dependencies.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var app = require('../app');
|
var app = require('../app');
|
||||||
var debug = require('debug')('bus-gateway:server');
|
var debug = require('debug')('bus-gateway:server');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
var axios = require('axios');
|
||||||
/**
|
var config = require('../config');
|
||||||
* Get port from environment and store in Express.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var port = normalizePort(process.env.PORT || '3000');
|
var port = normalizePort(process.env.PORT || '3000');
|
||||||
app.set('port', port);
|
app.set('port', port);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create HTTP server.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var server = http.createServer(app);
|
var server = http.createServer(app);
|
||||||
|
|
||||||
/**
|
const HAPI_HEALTH_URL = `${config.fhir.url}/metadata`;
|
||||||
* Listen on provided port, on all network interfaces.
|
const RETRY_DELAY_MS = 5000;
|
||||||
*/
|
const MAX_ATTEMPTS = 36; // 3 minutos máximo
|
||||||
|
|
||||||
server.listen(port);
|
async function waitForHapi() {
|
||||||
server.on('error', onError);
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
||||||
server.on('listening', onListening);
|
try {
|
||||||
|
await axios.get(HAPI_HEALTH_URL, { timeout: 5000 });
|
||||||
|
console.log(`[${new Date().toISOString()}] HAPI FHIR está listo`);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
console.log(`[${new Date().toISOString()}] Esperando HAPI FHIR (intento ${attempt}/${MAX_ATTEMPTS})...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.error(`[${new Date().toISOString()}] HAPI FHIR no respondió en el tiempo máximo de espera`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
waitForHapi().then(() => {
|
||||||
* Normalize a port into a number, string, or false.
|
server.listen(port);
|
||||||
*/
|
server.on('error', onError);
|
||||||
|
server.on('listening', onListening);
|
||||||
|
});
|
||||||
|
|
||||||
function normalizePort(val) {
|
function normalizePort(val) {
|
||||||
var port = parseInt(val, 10);
|
var port = parseInt(val, 10);
|
||||||
|
if (isNaN(port)) return val;
|
||||||
if (isNaN(port)) {
|
if (port >= 0) return port;
|
||||||
// named pipe
|
return false;
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port >= 0) {
|
|
||||||
// port number
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "error" event.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function onError(error) {
|
function onError(error) {
|
||||||
if (error.syscall !== 'listen') {
|
if (error.syscall !== 'listen') throw error;
|
||||||
throw error;
|
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
|
||||||
}
|
switch (error.code) {
|
||||||
|
case 'EACCES':
|
||||||
var bind = typeof port === 'string'
|
console.error(bind + ' requires elevated privileges');
|
||||||
? 'Pipe ' + port
|
process.exit(1);
|
||||||
: 'Port ' + port;
|
break;
|
||||||
|
case 'EADDRINUSE':
|
||||||
// handle specific listen errors with friendly messages
|
console.error(bind + ' is already in use');
|
||||||
switch (error.code) {
|
process.exit(1);
|
||||||
case 'EACCES':
|
break;
|
||||||
console.error(bind + ' requires elevated privileges');
|
default:
|
||||||
process.exit(1);
|
throw error;
|
||||||
break;
|
}
|
||||||
case 'EADDRINUSE':
|
|
||||||
console.error(bind + ' is already in use');
|
|
||||||
process.exit(1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event listener for HTTP server "listening" event.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function onListening() {
|
function onListening() {
|
||||||
var addr = server.address();
|
var addr = server.address();
|
||||||
var bind = typeof addr === 'string'
|
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
|
||||||
? 'pipe ' + addr
|
debug('Listening on ' + bind);
|
||||||
: 'port ' + addr.port;
|
console.log(`[${new Date().toISOString()}] bus-gateway escuchando en ${bind}`);
|
||||||
debug('Listening on ' + bind);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,26 +70,141 @@ function generateDocumentReferenceResource(subjectReference, bundleUrl) {
|
|||||||
|
|
||||||
async function getResourcesFromTransactionResponse(transactionResponse) {
|
async function getResourcesFromTransactionResponse(transactionResponse) {
|
||||||
const promises = transactionResponse.entry.map(async (e) => {
|
const promises = transactionResponse.entry.map(async (e) => {
|
||||||
const resource = getResourceByUrl(`${config.fhir.url}/${e.response.location}`);
|
const resource = await getResourceByUrl(`${config.fhir.url}/${e.response.location}`);
|
||||||
return resource;
|
return resource;
|
||||||
});
|
});
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ITI-65: Provide Document Bundle (MHD)
|
* Construye un Bundle de tipo transaction a partir de un Bundle de tipo document (IPS).
|
||||||
*
|
* Genera Patient, Bundle (IPS), DocumentReference y List (SubmissionSet MHD).
|
||||||
* POST /fhir/Bundle
|
* Usa urn:uuid: como fullUrl para que HAPI FHIR resuelva las referencias internas.
|
||||||
*
|
|
||||||
* Flow:
|
|
||||||
* 1. Store the IPS Bundle in HAPI FHIR.
|
|
||||||
* 2. Resolve the patient national identifier via Bus $match.
|
|
||||||
* 3. Register a DocumentReference in the Bus pointing to the stored Bundle.
|
|
||||||
*
|
|
||||||
* Required header:
|
|
||||||
* x-custodian-id — Efector identifier value in the Federador MSAL system.
|
|
||||||
*/
|
*/
|
||||||
async function provideDocumentBundle(req, res, next) {
|
function buildTransactionFromIPSDocument(ipsBundle) {
|
||||||
|
if (ipsBundle.type !== 'document') {
|
||||||
|
throw createError(400, 'Bundle must be of type document');
|
||||||
|
}
|
||||||
|
const patientEntry = (ipsBundle.entry || []).find(
|
||||||
|
e => e.resource && e.resource.resourceType === 'Patient'
|
||||||
|
);
|
||||||
|
if (!patientEntry) {
|
||||||
|
throw createError(400, 'IPS Bundle must contain a Patient resource');
|
||||||
|
}
|
||||||
|
|
||||||
|
const patientFullUrl = `urn:uuid:${uuidv4()}`;
|
||||||
|
const bundleFullUrl = `urn:uuid:${uuidv4()}`;
|
||||||
|
const documentReferenceFullUrl = `urn:uuid:${uuidv4()}`;
|
||||||
|
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
|
const localDocumentReference = {
|
||||||
|
resourceType: 'DocumentReference',
|
||||||
|
status: 'current',
|
||||||
|
masterIdentifier: {
|
||||||
|
use: 'usual',
|
||||||
|
system: MASTER_ID_SYSTEM,
|
||||||
|
value: `urn:uuid:${uuidv4()}`
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
coding: [{
|
||||||
|
system: 'http://loinc.org',
|
||||||
|
code: '60591-5',
|
||||||
|
display: 'Patient Summary Document',
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
date: now,
|
||||||
|
subject: { reference: patientFullUrl },
|
||||||
|
custodian: {
|
||||||
|
identifier: { system: CUSTODIAN_ID_SYSTEM, value: config.bus.issuer }
|
||||||
|
},
|
||||||
|
content: [{
|
||||||
|
attachment: {
|
||||||
|
url: bundleFullUrl,
|
||||||
|
contentType: 'application/fhir+json'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
const submissionSetList = {
|
||||||
|
resourceType: 'List',
|
||||||
|
status: 'current',
|
||||||
|
mode: 'working',
|
||||||
|
code: {
|
||||||
|
coding: [{
|
||||||
|
system: 'https://profiles.ihe.net/ITI/MHD/CodeSystem/MHDlistTypes',
|
||||||
|
code: 'submissionset'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
date: now,
|
||||||
|
subject: { reference: patientFullUrl },
|
||||||
|
source: {
|
||||||
|
identifier: { system: CUSTODIAN_ID_SYSTEM, value: config.bus.issuer }
|
||||||
|
},
|
||||||
|
entry: [
|
||||||
|
{ item: { reference: documentReferenceFullUrl } },
|
||||||
|
{ item: { reference: bundleFullUrl } }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
resourceType: 'Bundle',
|
||||||
|
type: 'transaction',
|
||||||
|
entry: [
|
||||||
|
{
|
||||||
|
fullUrl: patientFullUrl,
|
||||||
|
resource: patientEntry.resource,
|
||||||
|
request: { method: 'POST', url: 'Patient' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fullUrl: bundleFullUrl,
|
||||||
|
resource: ipsBundle,
|
||||||
|
request: { method: 'POST', url: 'Bundle' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fullUrl: documentReferenceFullUrl,
|
||||||
|
resource: localDocumentReference,
|
||||||
|
request: { method: 'POST', url: 'DocumentReference' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resource: submissionSetList,
|
||||||
|
request: { method: 'POST', url: 'List' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lógica central de ITI-65: persiste la transacción en HAPI FHIR, resuelve el
|
||||||
|
* paciente en el Bus y registra un DocumentReference apuntando al Bundle guardado.
|
||||||
|
*/
|
||||||
|
async function executeITI65(transaction, token) {
|
||||||
|
const transactionResponse = await processDocumentBundleTransaction(transaction);
|
||||||
|
const resources = await getResourcesFromTransactionResponse(transactionResponse);
|
||||||
|
|
||||||
|
const localPatient = extractResource(resources, PATIENT_RESOURCE_TYPE);
|
||||||
|
const localIPSDocument = extractResource(resources, IPS_DOCUMENT_RESOURCE_TYPE);
|
||||||
|
const localPatientIdentifier = extractLocalIdentifier(localPatient);
|
||||||
|
|
||||||
|
const patientSearchset = await findPatient(token, { identifier: `${localPatientIdentifier.system}|${localPatientIdentifier.value}` });
|
||||||
|
if (patientSearchset.total == 0) {
|
||||||
|
throw createError(404, 'Patient does not exists');
|
||||||
|
}
|
||||||
|
const nationalPatientId = patientSearchset.entry[0].fullUrl;
|
||||||
|
const bundleReference = `${config.baseURL}/fhir/Bundle/${localIPSDocument.id}`;
|
||||||
|
|
||||||
|
const documentReference = generateDocumentReferenceResource(nationalPatientId, bundleReference);
|
||||||
|
return createDocumentReference(token, documentReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ITI-65: Provide Document Bundle (MHD) — variante transacción
|
||||||
|
*
|
||||||
|
* POST /fhir/iti65
|
||||||
|
*
|
||||||
|
* Espera un Bundle de tipo transaction construido por el cliente.
|
||||||
|
*/
|
||||||
|
async function provideIPSTransaction(req, res, next) {
|
||||||
try {
|
try {
|
||||||
const transaction = req.body;
|
const transaction = req.body;
|
||||||
const token = await getBusToken(
|
const token = await getBusToken(
|
||||||
@ -98,36 +213,39 @@ async function provideDocumentBundle(req, res, next) {
|
|||||||
config.bus.issuer,
|
config.bus.issuer,
|
||||||
[config.bus.mpiScope, config.bus.documentRegistryScope].join(',')
|
[config.bus.mpiScope, config.bus.documentRegistryScope].join(',')
|
||||||
);
|
);
|
||||||
|
const result = await executeITI65(transaction, token);
|
||||||
// Paso 1: Ejecuto la transcción en el servidor hapi subyacente
|
return res.status(200).json(result);
|
||||||
const transactionResponse = await processDocumentBundleTransaction(transaction);
|
|
||||||
|
|
||||||
const resources = await getResourcesFromTransactionResponse(transactionResponse);
|
|
||||||
|
|
||||||
// Paso 2: Obtengo el paciente local (tal como se guardo en la trasnaccion)
|
|
||||||
const localPatient = extractResource(resources, PATIENT_RESOURCE_TYPE);
|
|
||||||
// Paso 3: Obtengo el documento IPS local (tal como se guardo en la transacción)
|
|
||||||
const localIPSDocument = extractResource(resources, IPS_DOCUMENT_RESOURCE_TYPE)
|
|
||||||
|
|
||||||
const localPatientIdentifier = extractLocalIdentifier(localPatient);
|
|
||||||
|
|
||||||
const patientSearchset = await findPatient(token, { identifier: `${localPatientIdentifier.system}|${localPatientIdentifier.value}` });
|
|
||||||
if (patientSearchset.total == 0) {
|
|
||||||
throw createError(404, 'Patient does not exists');
|
|
||||||
}
|
|
||||||
const nationalPatientId = patientSearchset.entry[0].fullUrl;
|
|
||||||
const bundleReference = `${config.baseURL}/fhir/Bundle/${localIPSDocument.id}`;
|
|
||||||
|
|
||||||
|
|
||||||
const documentReference = generateDocumentReferenceResource(nationalPatientId, bundleReference);
|
|
||||||
|
|
||||||
const createdDocumentReference = await createDocumentReference(token, documentReference);
|
|
||||||
|
|
||||||
return res.status(200).json(createdDocumentReference);
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next(err);
|
next(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { provideDocumentBundle };
|
/**
|
||||||
|
* ITI-65: Provide Document Bundle (MHD) — variante IPS document
|
||||||
|
*
|
||||||
|
* POST /fhir/Bundle
|
||||||
|
*
|
||||||
|
* Espera un Bundle de tipo document (IPS). Genera internamente el Bundle
|
||||||
|
* transaction y ejecuta el mismo flujo que provideDocumentBundle.
|
||||||
|
*/
|
||||||
|
async function provideIPSDocumentBundle(req, res, next) {
|
||||||
|
try {
|
||||||
|
const ipsBundle = req.body;
|
||||||
|
if (!ipsBundle || ipsBundle.resourceType !== 'Bundle') {
|
||||||
|
throw createError(400, 'Request body must be a FHIR Bundle resource');
|
||||||
|
}
|
||||||
|
const transaction = buildTransactionFromIPSDocument(ipsBundle);
|
||||||
|
const token = await getBusToken(
|
||||||
|
config.bus.url,
|
||||||
|
config.bus.jwtSecret,
|
||||||
|
config.bus.issuer,
|
||||||
|
[config.bus.mpiScope, config.bus.documentRegistryScope].join(',')
|
||||||
|
);
|
||||||
|
const result = await executeITI65(transaction, token);
|
||||||
|
return res.status(200).json(result);
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { provideIPSTransaction, provideIPSDocumentBundle };
|
||||||
|
|||||||
@ -1,46 +0,0 @@
|
|||||||
const createError = require('http-errors');
|
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ITI-68: Retrieve Document (MHD)
|
|
||||||
*
|
|
||||||
* GET /fhir/Binary?url=[URL_Directa]
|
|
||||||
*
|
|
||||||
* Flow (diagram iti67.mmd, step 21-24):
|
|
||||||
* 1. HIS_A supplies the direct document URL obtained from a prior ITI-67 response.
|
|
||||||
* 2. This gateway performs a P2P GET to that URL, bypassing the Bus.
|
|
||||||
* 3. The raw document (PDF, XML, etc.) is forwarded back to HIS_A.
|
|
||||||
*/
|
|
||||||
async function getBundleById(req, res, next) {
|
|
||||||
try {
|
|
||||||
const url = req.query.url;
|
|
||||||
if (!url) {
|
|
||||||
throw createError(400, 'Missing required query parameter: url');
|
|
||||||
}
|
|
||||||
let parsedUrl;
|
|
||||||
try {
|
|
||||||
parsedUrl = new URL(url);
|
|
||||||
} catch {
|
|
||||||
throw createError(400, 'Invalid document URL');
|
|
||||||
}
|
|
||||||
const response = await getDocumentBundleByUrl(url);
|
|
||||||
|
|
||||||
const contentType = response.headers['content-type'];
|
|
||||||
if (contentType) res.setHeader('Content-Type', contentType);
|
|
||||||
|
|
||||||
const contentDisposition = response.headers['content-disposition'];
|
|
||||||
if (contentDisposition) res.setHeader('Content-Disposition', contentDisposition);
|
|
||||||
|
|
||||||
res.status(200).send(response.data);
|
|
||||||
} catch (err) {
|
|
||||||
if (err.response) {
|
|
||||||
return next(createError(err.response.status, `Document source returned ${err.response.status}`));
|
|
||||||
}
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { getBundleById };
|
|
||||||
@ -3,8 +3,7 @@ const router = express.Router();
|
|||||||
const { createPatient, updatePatient } = require('../controllers/iti104');
|
const { createPatient, updatePatient } = require('../controllers/iti104');
|
||||||
|
|
||||||
// ITI-104: Patient Identity Feed FHIR
|
// ITI-104: Patient Identity Feed FHIR
|
||||||
// TODO: Cambiar ruta por ITI104
|
router.post('/Patient', createPatient);
|
||||||
router.post('/iti104', createPatient);
|
router.put('/Patient/:id', updatePatient);
|
||||||
router.put('/iti104/:id', updatePatient);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { provideDocumentBundle } = require('../controllers/iti65');
|
const { provideIPSTransaction, provideIPSDocumentBundle } = require('../controllers/iti65');
|
||||||
|
|
||||||
// ITI-65: Provide Document Bundle
|
// ITI-65: Provide Document Bundle — variante transaction Bundle
|
||||||
// TODO: Cambiar la ruta de acceso para que no se confunda con el recurso Bundle cambiar por iti65
|
router.post('/IPSTransaction', provideIPSTransaction);
|
||||||
router.post('/iti65', provideDocumentBundle);
|
|
||||||
|
// ITI-65: Provide Document Bundle — variante IPS document Bundle (type: document)
|
||||||
|
router.post('/IPSDocument', provideIPSDocumentBundle);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ const router = express.Router();
|
|||||||
const { listDocumentReference } = require('../controllers/iti67');
|
const { listDocumentReference } = require('../controllers/iti67');
|
||||||
|
|
||||||
// ITI-67: Find Document References
|
// ITI-67: Find Document References
|
||||||
// TODO: Cambiar ruta por ITI67
|
router.get('/DocumentReference', listDocumentReference);
|
||||||
router.get('/iti67', listDocumentReference);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const { getBundleById } = require('../controllers/iti68');
|
|
||||||
|
|
||||||
// ITI-68: Retrieve Document → GET /fhir/Binary?url=[URL_Directa]
|
|
||||||
router.get('/Bundle', getBundleById);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@ -3,8 +3,7 @@ const router = express.Router();
|
|||||||
const { listPatient, getPatientById } = require('../controllers/iti78');
|
const { listPatient, getPatientById } = require('../controllers/iti78');
|
||||||
|
|
||||||
// ITI-78: Mobile Patient Demographics Query
|
// ITI-78: Mobile Patient Demographics Query
|
||||||
// TOOD: Cambiar ruta por ITI78
|
router.get('/Patient', listPatient);
|
||||||
router.get('/iti78', listPatient);
|
router.get('/Patient/:id', getPatientById);
|
||||||
router.get('/iti78/:id', getPatientById);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
hapi-fhir:
|
hapi-fhir:
|
||||||
|
container_name: hapi-fhir
|
||||||
image: "hapiproject/hapi:latest"
|
image: "hapiproject/hapi:latest"
|
||||||
depends_on:
|
depends_on:
|
||||||
- hapi-db
|
- hapi-db
|
||||||
@ -15,8 +16,8 @@ services:
|
|||||||
SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT: ${SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT}
|
SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT: ${SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT}
|
||||||
networks:
|
networks:
|
||||||
- hapi-network
|
- hapi-network
|
||||||
|
|
||||||
hapi-db:
|
hapi-db:
|
||||||
|
container_name: hapi-db
|
||||||
image: "postgres:14.6"
|
image: "postgres:14.6"
|
||||||
restart: always
|
restart: always
|
||||||
user: root
|
user: root
|
||||||
@ -42,19 +43,19 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8182:8080
|
- 8182:8080
|
||||||
secrets:
|
secrets:
|
||||||
- signature-cert
|
- trust-network-cert
|
||||||
|
- trust-network-key
|
||||||
- signature-key
|
- signature-key
|
||||||
- dsc-key
|
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_DB=gdhcn-validator
|
- POSTGRES_DB=gdhcn-validator
|
||||||
- SERVER_PORT=8080
|
- SERVER_PORT=8080
|
||||||
- SPRING_DATASOURCE_URL=jdbc:postgresql://gdhcn-db:5432/gdhcn-validator
|
- SPRING_DATASOURCE_URL=jdbc:postgresql://gdhcn-db:5432/gdhcn-validator
|
||||||
- SPRING_DATASOURCE_USERNAME=root
|
- SPRING_DATASOURCE_USERNAME=root
|
||||||
- SPRING_DATASOURCE_PASSWORD=root
|
- SPRING_DATASOURCE_PASSWORD=root
|
||||||
- TNG_TLS_PEM=/run/secrets/signature-cert
|
- TNG_TLS_PEM=/run/secrets/trust-network-cert
|
||||||
- TNG_TLS_KEY=/run/secrets/signature-key
|
- TNG_TLS_KEY=/run/secrets/trust-network-key
|
||||||
- TNG_DSC_PRIVATEKEY=/run/secrets/dsc-key
|
- TNG_DSC_PRIVATEKEY=/run/secrets/signature-key
|
||||||
- TNG_COUNTRY=XJ
|
- TNG_COUNTRY=AR
|
||||||
- TNG_DSC_PRIVATEKEY_KID=I1BAX8FATLs=
|
- TNG_DSC_PRIVATEKEY_KID=I1BAX8FATLs=
|
||||||
- GDHCN_BASEURL=${NODO_BASE_URL:-http://localhost}/gdhcn
|
- GDHCN_BASEURL=${NODO_BASE_URL:-http://localhost}/gdhcn
|
||||||
networks:
|
networks:
|
||||||
@ -63,6 +64,7 @@ services:
|
|||||||
- ./json:/json
|
- ./json:/json
|
||||||
|
|
||||||
gdhcn-db:
|
gdhcn-db:
|
||||||
|
container_name: gdhcn-db
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
@ -75,6 +77,7 @@ services:
|
|||||||
- POSTGRES_PASSWORD=root
|
- POSTGRES_PASSWORD=root
|
||||||
|
|
||||||
bus-gateway:
|
bus-gateway:
|
||||||
|
container_name: bus-gateway
|
||||||
build:
|
build:
|
||||||
context: ./bus-gateway
|
context: ./bus-gateway
|
||||||
environment:
|
environment:
|
||||||
@ -96,6 +99,7 @@ services:
|
|||||||
command: node --inspect=0.0.0.0:9229 ./bin/www
|
command: node --inspect=0.0.0.0:9229 ./bin/www
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
|
container_name: nginx
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
depends_on:
|
depends_on:
|
||||||
- hapi-fhir
|
- hapi-fhir
|
||||||
@ -130,9 +134,9 @@ secrets:
|
|||||||
file: ${SSL_CERT_PATH:-./certs/server.crt}
|
file: ${SSL_CERT_PATH:-./certs/server.crt}
|
||||||
ssl_key:
|
ssl_key:
|
||||||
file: ${SSL_KEY_PATH:-./certs/server.key}
|
file: ${SSL_KEY_PATH:-./certs/server.key}
|
||||||
signature-cert:
|
trust-network-cert:
|
||||||
file: ${SIGNATURE_CERT_PATH:-./certs/signature.crt}
|
file: ${SIGNATURE_CERT_PATH:-./certs/trust-network.pem}
|
||||||
|
trust-network-key:
|
||||||
|
file: ${SIGNATURE_KEY_PATH:-./certs/trust-network.key}
|
||||||
signature-key:
|
signature-key:
|
||||||
file: ${SIGNATURE_KEY_PATH:-./certs/signature.key}
|
file: ${SSL_DCC_KEY_PATH:-./certs/signature.key}
|
||||||
dsc-key:
|
|
||||||
file: ${SSL_DCC_KEY_PATH:-./certs/dcc.key}
|
|
||||||
|
|||||||
@ -14,7 +14,9 @@ http {
|
|||||||
server_name _;
|
server_name _;
|
||||||
|
|
||||||
# Rutas del bus-gateway (prefijo más específico gana sobre /fhir/)
|
# Rutas del bus-gateway (prefijo más específico gana sobre /fhir/)
|
||||||
location /fhir/iti65 {
|
|
||||||
|
# ITI-65: Provide Document Bundle — transaction Bundle
|
||||||
|
location /fhir/IPSTransaction {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -23,7 +25,8 @@ http {
|
|||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /fhir/iti67 {
|
# ITI-65: Provide Document Bundle — IPS document Bundle
|
||||||
|
location /fhir/IPSDocument {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -32,7 +35,8 @@ http {
|
|||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /fhir/iti78 {
|
# ITI-67: Find Document References
|
||||||
|
location /fhir/DocumentReference {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -40,7 +44,10 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
location /fhir/iti104 {
|
|
||||||
|
# ITI-78: Mobile Patient Demographics Query
|
||||||
|
# ITI-104: Patient Identity Feed FHIR
|
||||||
|
location /fhir/Patient {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -48,14 +55,16 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /vhl/ {
|
location /vhl/ {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Resto de /fhir/* va a hapi-fhir
|
# Resto de /fhir/* va a hapi-fhir
|
||||||
location /fhir/ {
|
location /fhir/ {
|
||||||
proxy_pass http://hapi_fhir;
|
proxy_pass http://hapi_fhir;
|
||||||
@ -74,6 +83,7 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Todo lo demás va a hapi-fhir
|
# Todo lo demás va a hapi-fhir
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://hapi_fhir;
|
proxy_pass http://hapi_fhir;
|
||||||
|
|||||||
@ -30,8 +30,9 @@ http {
|
|||||||
ssl_session_timeout 10m;
|
ssl_session_timeout 10m;
|
||||||
|
|
||||||
# Rutas del bus-gateway (prefijo más específico gana sobre /fhir/)
|
# Rutas del bus-gateway (prefijo más específico gana sobre /fhir/)
|
||||||
# Rutas del bus-gateway (prefijo más específico gana sobre /fhir/)
|
|
||||||
location /fhir/iti65 {
|
# ITI-65: Provide Document Bundle — transaction Bundle
|
||||||
|
location /fhir/IPSTransaction {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -40,7 +41,8 @@ http {
|
|||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /fhir/iti67 {
|
# ITI-65: Provide Document Bundle — IPS document Bundle
|
||||||
|
location /fhir/IPSDocument {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -49,7 +51,8 @@ http {
|
|||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /fhir/iti78 {
|
# ITI-67: Find Document References
|
||||||
|
location /fhir/DocumentReference {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -57,7 +60,10 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
location /fhir/iti104 {
|
|
||||||
|
# ITI-78: Mobile Patient Demographics Query
|
||||||
|
# ITI-104: Patient Identity Feed FHIR
|
||||||
|
location /fhir/Patient {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
@ -65,14 +71,16 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /vhl/ {
|
location /vhl/ {
|
||||||
proxy_pass http://bus_gateway;
|
proxy_pass http://bus_gateway;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Resto de /fhir/* va a hapi-fhir
|
# Resto de /fhir/* va a hapi-fhir
|
||||||
location /fhir/ {
|
location /fhir/ {
|
||||||
proxy_pass http://hapi_fhir;
|
proxy_pass http://hapi_fhir;
|
||||||
@ -91,6 +99,7 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_read_timeout 90s;
|
proxy_read_timeout 90s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Todo lo demás va a hapi-fhir
|
# Todo lo demás va a hapi-fhir
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://hapi_fhir;
|
proxy_pass http://hapi_fhir;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user