TL;DR
HL7 FHIR (Fast Healthcare Interoperability Resources) é o padrão moderno para troca de dados de saúde, usando APIs RESTful com respostas JSON/XML. Ele fornece recursos padronizados para pacientes, observações, medicamentos e muito mais, com autenticação OAuth 2.0 e SMART on FHIR para integração de aplicativos. Este guia abrange a arquitetura FHIR, tipos de recursos, parâmetros de busca, autenticação e estratégias de implementação em produção.
💡 Dica: Apidog simplifica a integração de APIs de saúde. Teste endpoints FHIR, valide esquemas de recursos, depure fluxos de autenticação e documente especificações de API em um único espaço de trabalho. Importe Guias de Implementação FHIR, simule respostas e compartilhe cenários de teste com sua equipe.
O Que É HL7 FHIR?
FHIR (Fast Healthcare Interoperability Resources) é uma estrutura de padrões para troca eletrônica de informações de saúde. Desenvolvido pela Health Level Seven International (HL7), o FHIR utiliza APIs RESTful, JSON, XML e OAuth 2.0.
Tipos de Recursos FHIR
FHIR define mais de 140 tipos de recursos. Os principais para implementar:
| Recurso | Propósito | Casos de Uso Comuns |
|---|---|---|
| Patient (Paciente) | Demográficos | Consulta de pacientes, registro |
| Practitioner (Profissional) | Informações do provedor | Diretório, agendamento |
| Encounter (Atendimento) | Consultas/internações | Episódios de cuidado, faturamento |
| Observation (Observação) | Dados clínicos | Sinais vitais, resultados de laboratório, avaliações |
| Condition (Condição) | Problemas/diagnósticos | Listas de problemas, plano de cuidados |
| MedicationRequest (Solicitação de Medicação) | Prescrições | Prescrição eletrônica, histórico de medicação |
| AllergyIntolerance (AlergiaIntolerância) | Alergias | Verificações de segurança, alertas |
| Immunization (Imunização) | Vacinações | Registros de imunização |
| DiagnosticReport (Relatório Diagnóstico) | Relatórios de laboratório/imagem | Entrega de resultados |
| DocumentReference (Referência de Documento) | Documentos clínicos | CCD, sumários de alta |
Arquitetura da API FHIR
A estrutura básica do endpoint RESTful é:
https://fhir-server.com/fhir/{resourceType}/{id}
Versões FHIR Comparadas
| Versão | Status | Caso de Uso |
|---|---|---|
| R4 (4.0.1) | STU Atual | Implementações em produção |
| R4B (4.3) | Implementação de Teste | Adotantes iniciais |
| R5 (5.0.0) | Rascunho STU | Futuras implementações |
| DSTU2 | Obsoleto | Apenas sistemas legados |
O CMS exige suporte ao FHIR R4 em APIs de acesso ao paciente e provedor.
Primeiros Passos: Acesso ao Servidor FHIR
Passo 1: Escolha Seu Servidor FHIR
Opções de servidores para ambientes reais e testes:
| Servidor | Tipo | Custo | Melhor Para |
|---|---|---|---|
| Azure API for FHIR | Gerenciado | Pagamento por uso | Empresas, usuários Azure |
| AWS HealthLake | Gerenciado | Pagamento por uso | Ambientes AWS |
| Google Cloud Healthcare API | Gerenciado | Pagamento por uso | Ambientes GCP |
| HAPI FHIR | Código Aberto | Auto-hospedado | Implantações personalizadas |
| Epic FHIR Server | Comercial | Clientes Epic | Integração com EHR Epic |
| Cerner Ignite FHIR | Comercial | Clientes Cerner | Integração com EHR Cerner |
Passo 2: Obtenha as Credenciais do Servidor
Exemplo para cloud:
# Azure API for FHIR
# 1. Crie o Serviço FHIR no Portal Azure
# 2. Configure a autenticação (OAuth 2.0 ou AAD)
# 3. Obtenha o endpoint FHIR: https://{nome-do-serviço}.azurehealthcareapis.com
# 4. Registre o aplicativo cliente para OAuth
# AWS HealthLake
# 1. Crie o Data Store no Console AWS
# 2. Configure as funções IAM
# 3. Obtenha o endpoint: https://healthlake.{região}.amazonaws.com
Passo 3: Entenda as Operações RESTful do FHIR
| Operação | Método HTTP | Endpoint | Descrição |
|---|---|---|---|
| Read (Ler) | GET | /{resourceType}/{id} |
Obter recurso específico |
| Search (Buscar) | GET | /{resourceType}?param=value |
Buscar recursos |
| Create (Criar) | POST | /{resourceType} |
Criar novo recurso |
| Update (Atualizar) | PUT | /{resourceType}/{id} |
Substituir recurso |
| Patch (Aplicar Patch) | PATCH | /{resourceType}/{id} |
Atualização parcial |
| Delete (Excluir) | DELETE | /{resourceType}/{id} |
Remover recurso |
| History (Histórico) | GET | /{resourceType}/{id}/_history |
Versões do recurso |
Passo 4: Faça Sua Primeira Chamada FHIR
Teste a conectividade:
curl -X GET "https://fhir-server.com/fhir/metadata" \
-H "Accept: application/fhir+json" \
-H "Authorization: Bearer {token}"
Resposta esperada:
{
"resourceType": "CapabilityStatement",
"status": "active",
"date": "2026-03-25",
"fhirVersion": "4.0.1",
"rest": [{
"mode": "server",
"resource": [
{ "type": "Patient" },
{ "type": "Observation" },
{ "type": "Condition" }
]
}]
}
Operações FHIR Essenciais
Lendo um Recurso de Paciente
Busque paciente por ID:
const FHIR_BASE_URL = process.env.FHIR_BASE_URL;
const FHIR_TOKEN = process.env.FHIR_TOKEN;
const fhirRequest = async (endpoint, options = {}) => {
const response = await fetch(`${FHIR_BASE_URL}/fhir${endpoint}`, {
...options,
headers: {
'Accept': 'application/fhir+json',
'Authorization': `Bearer ${FHIR_TOKEN}`,
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`FHIR Error: ${error.issue?.[0]?.details?.text || response.statusText}`);
}
return response.json();
};
// Ler paciente por ID
const getPatient = async (patientId) => {
const patient = await fhirRequest(`/Patient/${patientId}`);
return patient;
};
// Uso
const patient = await getPatient('12345');
console.log(`Paciente: ${patient.name[0].given[0]} ${patient.name[0].family}`);
console.log(`Data de Nascimento: ${patient.birthDate}`);
console.log(`Gênero: ${patient.gender}`);
Estrutura do Recurso de Paciente
{
"resourceType": "Patient",
"id": "12345",
"identifier": [
{
"use": "usual",
"type": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR"
}]
},
"system": "http://hospital.example.org",
"value": "MRN123456"
}
],
"name": [
{
"use": "official",
"family": "Smith",
"given": ["John", "Michael"]
}
],
"telecom": [
{
"system": "phone",
"value": "555-123-4567",
"use": "home"
},
{
"system": "email",
"value": "john.smith@email.com"
}
],
"gender": "male",
"birthDate": "1985-06-15",
"address": [
{
"use": "home",
"line": ["123 Main Street"],
"city": "Springfield",
"state": "IL",
"postalCode": "62701"
}
]
}
Buscando Recursos
Busque pacientes por nome:
const searchPatients = async (searchParams) => {
const query = new URLSearchParams();
if (searchParams.name) query.append('name', searchParams.name);
if (searchParams.birthDate) query.append('birthdate', searchParams.birthDate);
if (searchParams.identifier) query.append('identifier', searchParams.identifier);
if (searchParams.gender) query.append('gender', searchParams.gender);
const response = await fhirRequest(`/Patient?${query.toString()}`);
return response;
};
// Uso
const results = await searchPatients({ name: 'Smith', birthDate: '1985-06-15' });
console.log(`Encontrados ${results.total} pacientes`);
results.entry.forEach(entry => {
const patient = entry.resource;
console.log(`${patient.name[0].family}, ${patient.name[0].given[0]}`);
});
Parâmetros de Busca Comuns
| Recurso | Parâmetros de Busca | Exemplo |
|---|---|---|
| Patient (Paciente) | name, birthdate, identifier, gender, phone, email | ?name=Smith&birthdate=1985-06-15 |
| Observation (Observação) | patient, code, date, category, status | ?patient=123&code=8480-6&date=ge2026-01-01 |
| Condition (Condição) | patient, clinical-status, category, onset-date | ?patient=123&clinical-status=active |
| MedicationRequest (Solicitação de Medicação) | patient, status, intent, medication | ?patient=123&status=active |
| Encounter (Atendimento) | patient, date, status, class | ?patient=123&date=ge2026-01-01 |
| DiagnosticReport (Relatório Diagnóstico) | patient, category, date, status | ?patient=123&category=laboratory |
Modificadores de Busca
| Modificador | Descrição | Exemplo |
|---|---|---|
:exact |
Correspondência exata | name:exact=Smith |
:contains |
Contém | name:contains=smi |
:missing |
Valor presente/ausente | phone:missing=true |
: (prefixo) |
Operadores de prefixo | birthdate=ge1980-01-01 |
Prefixos de Busca para Datas e Números
| Prefixo | Significado | Exemplo |
|---|---|---|
eq |
Igual a | birthdate=eq1985-06-15 |
ne |
Diferente de | birthdate=ne1985-06-15 |
gt |
Maior que | birthdate=gt1980-01-01 |
lt |
Menor que | birthdate=lt1990-01-01 |
ge |
Maior ou igual a | birthdate=ge1980-01-01 |
le |
Menor ou igual a | birthdate=le1990-01-01 |
sa |
Começa depois de | date=sa2026-01-01 |
eb |
Termina antes de | date=eb2026-12-31 |
Trabalhando com Dados Clínicos
Criando uma Observação (Sinais Vitais)
Registrar sinais vitais:
const createObservation = async (observationData) => {
const observation = {
resourceType: 'Observation',
status: 'final',
category: [
{
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/observation-category',
code: 'vital-signs'
}]
}
],
code: {
coding: [{
system: 'http://loinc.org',
code: observationData.code,
display: observationData.display
}]
},
subject: {
reference: `Patient/${observationData.patientId}`
},
effectiveDateTime: observationData.effectiveDate || new Date().toISOString(),
valueQuantity: {
value: observationData.value,
unit: observationData.unit,
system: 'http://unitsofmeasure.org',
code: observationData.ucumCode
},
performer: [
{
reference: `Practitioner/${observationData.performerId}`
}
]
};
const response = await fhirRequest('/Observation', {
method: 'POST',
body: JSON.stringify(observation)
});
return response;
};
// Uso - Registrar pressão arterial
const systolicBP = await createObservation({
patientId: '12345',
code: '8480-6',
display: 'Pressão arterial sistólica',
value: 120,
unit: 'mmHg',
ucumCode: 'mm[Hg]',
performerId: '67890'
});
console.log(`Observação criada: ${systolicBP.id}`);
Códigos LOINC Comuns
| Código | Exibição | Categoria |
|---|---|---|
| 8480-6 | Pressão arterial sistólica | Sinais vitais |
| 8462-4 | Pressão arterial diastólica | Sinais vitais |
| 8867-4 | Frequência cardíaca | Sinais vitais |
| 8310-5 | Temperatura corporal | Sinais vitais |
| 8302-2 | Altura corporal | Sinais vitais |
| 29463-7 | Peso corporal | Sinais vitais |
| 8871-5 | Frequência respiratória | Sinais vitais |
| 2339-0 | Glicose [Massa/volume] | Laboratório |
| 4548-4 | Hemoglobina A1c | Laboratório |
| 2093-3 | Colesterol [Massa/volume] | Laboratório |
Criando uma Condição (Entrada na Lista de Problemas)
Adicionar diagnóstico:
const createCondition = async (conditionData) => {
const condition = {
resourceType: 'Condition',
clinicalStatus: {
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-clinical',
code: conditionData.status || 'active'
}]
},
verificationStatus: {
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-ver-status',
code: 'confirmed'
}]
},
category: [
{
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-category',
code: conditionData.category || 'problem-list-item'
}]
}
],
code: {
coding: [{
system: 'http://snomed.info/sct',
code: conditionData.sctCode,
display: conditionData.display
}]
},
subject: {
reference: `Patient/${conditionData.patientId}`
},
onsetDateTime: conditionData.onsetDate,
recordedDate: new Date().toISOString()
};
const response = await fhirRequest('/Condition', {
method: 'POST',
body: JSON.stringify(condition)
});
return response;
};
// Uso - Adicionar diabetes à lista de problemas
const diabetes = await createCondition({
patientId: '12345',
sctCode: '44054006',
display: 'Diabetes Mellitus Tipo 2',
status: 'active',
category: 'problem-list-item',
onsetDate: '2024-01-15'
});
Códigos SNOMED CT Comuns
| Código | Exibição | Categoria |
|---|---|---|
| 44054006 | Diabetes Mellitus Tipo 2 | Problema |
| 38341003 | Hipertensão | Problema |
| 195967001 | Asma | Problema |
| 13645005 | Doença Pulmonar Obstrutiva Crônica | Problema |
| 35489007 | Transtorno Depressivo | Problema |
| 22298006 | Infarto do Miocárdio | Problema |
| 26929004 | Doença de Alzheimer | Problema |
| 396275006 | Osteoartrite | Problema |
Recuperando Medicações do Paciente
Obtenha solicitações de medicação ativas:
const getPatientMedications = async (patientId) => {
const response = await fhirRequest(
`/MedicationRequest?patient=${patientId}&status=active`
);
return response;
};
// Uso
const medications = await getPatientMedications('12345');
medications.entry?.forEach(entry => {
const med = entry.resource;
console.log(`${med.medicationCodeableConcept.coding[0].display}`);
console.log(` Dose: ${med.dosageInstruction[0]?.text}`);
console.log(` Status: ${med.status}`);
});
Recuperando Resultados de Laboratório
Obtenha relatórios diagnósticos e observações:
const getPatientLabResults = async (patientId, options = {}) => {
const params = new URLSearchParams({
patient: patientId,
category: options.category || 'laboratory'
});
if (options.dateFrom) {
params.append('date', `ge${options.dateFrom}`);
}
const response = await fhirRequest(`/DiagnosticReport?${params.toString()}`);
return response;
};
// Obter teste de laboratório específico (ex.: HbA1c)
const getLabValue = async (patientId, loincCode) => {
const params = new URLSearchParams({
patient: patientId,
code: loincCode
});
const response = await fhirRequest(`/Observation?${params.toString()}`);
return response;
};
// Uso - Obter resultados de HbA1c
const hba1c = await getLabValue('12345', '4548-4');
hba1c.entry?.forEach(entry => {
const obs = entry.resource;
console.log(`HbA1c: ${obs.valueQuantity.value} ${obs.valueQuantity.unit}`);
console.log(`Data: ${obs.effectiveDateTime}`);
});
OAuth 2.0 e SMART on FHIR
Entendendo a Autenticação FHIR
Fluxo típico OAuth 2.0/OpenID Connect:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Cliente │───▶│ Servidor │───▶│ Servidor │
│ (App) │ │ de Auth │ │ FHIR │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ 1. Solicitação │ │
│ de Auth │ │
│───────────────────▶│ │
│ │ │
│ 2. Login do │ │
│ Usuário │ │
│◀───────────────────│ │
│ │ │
│ 3. Código │ │
│ de Auth │ │
│───────────────────▶│ │
│ │ │
│ 4. Solicitação │ │
│ de Token │ │
│───────────────────▶│ │
│ │ 5. Token + ID │
│◀───────────────────│ │
│ │ │
│ 6. Solicitação │ │
│ de API │ │
│────────────────────────────────────────▶│
│ │ │
│ 7. Dados FHIR │ │
│◀────────────────────────────────────────│
Lançamento de Aplicativo SMART on FHIR
Implementação básica em Node.js:
const crypto = require('crypto');
class SMARTClient {
constructor(config) {
this.clientId = config.clientId;
this.redirectUri = config.redirectUri;
this.issuer = config.issuer;
this.scopes = config.scopes;
}
generatePKCE() {
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
return { codeVerifier, codeChallenge };
}
buildAuthUrl(state, patientId = null) {
const { codeVerifier, codeChallenge } = this.generatePKCE();
this.codeVerifier = codeVerifier;
const params = new URLSearchParams({
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: this.scopes.join(' '),
state: state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
aud: this.issuer,
launch: patientId ? `patient-${patientId}` : null
});
return `${this.issuer}/authorize?${params.toString()}`;
}
async exchangeCodeForToken(code) {
const response = await fetch(`${this.issuer}/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: this.redirectUri,
client_id: this.clientId,
code_verifier: this.codeVerifier
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
patientId: data.patient,
encounterId: data.encounter
};
}
}
// Uso
const smartClient = new SMARTClient({
clientId: 'my-app-client-id',
redirectUri: 'https://myapp.com/callback',
issuer: 'https://fhir.epic.com',
scopes: [
'openid',
'profile',
'patient/Patient.read',
'patient/Observation.read',
'patient/Condition.read',
'patient/MedicationRequest.read',
'offline_access'
]
});
// Redirecionar usuário para a URL de autenticação
const state = crypto.randomBytes(16).toString('hex');
const authUrl = smartClient.buildAuthUrl(state);
console.log(`Redirecionar para: ${authUrl}`);
Escopos SMART Necessários
| Escopo | Permissão | Caso de Uso |
|---|---|---|
openid |
Autenticação OIDC | Obrigatório para todos os aplicativos |
profile |
Informações de perfil do usuário | Diretório do provedor |
patient/Patient.read |
Ler dados demográficos do paciente | Pesquisa de paciente |
patient/Observation.read |
Ler observações | Sinais vitais, exames laboratoriais |
patient/Condition.read |
Ler condições | Listas de problemas |
patient/MedicationRequest.read |
Ler medicações | Histórico de medicação |
patient/*.read |
Ler todos os recursos do paciente | Dados completos do paciente |
user/*.read |
Ler todos os recursos acessíveis | Visão do provedor |
offline_access |
Atualizar token | Sessões de longa duração |
Fazendo Requisições FHIR Autenticadas
class FHIRClient {
constructor(accessToken, fhirBaseUrl) {
this.accessToken = accessToken;
this.baseUrl = fhirBaseUrl;
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}/fhir${endpoint}`, {
...options,
headers: {
'Accept': 'application/fhir+json',
'Authorization': `Bearer ${this.accessToken}`,
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Erro FHIR: ${error.issue?.[0]?.details?.text}`);
}
return response.json();
}
async getPatient(patientId) {
return this.request(`/Patient/${patientId}`);
}
async searchPatients(params) {
const query = new URLSearchParams(params);
return this.request(`/Patient?${query.toString()}`);
}
}
// Uso após o callback OAuth
const fhirClient = new FHIRClient(tokens.accessToken, 'https://fhir.epic.com');
const patient = await fhirClient.getPatient(tokens.patientId);
Operações em Lote e Transacionais
Requisições em Lote
Execute requisições paralelas:
const batchRequest = async (requests) => {
const bundle = {
resourceType: 'Bundle',
type: 'batch',
entry: requests.map(req => ({
resource: req.resource,
request: {
method: req.method,
url: req.url
}
}))
};
const response = await fhirRequest('', {
method: 'POST',
body: JSON.stringify(bundle)
});
return response;
};
// Uso - Buscar múltiplos recursos
const bundle = await batchRequest([
{ method: 'GET', url: 'Patient/12345' },
{ method: 'GET', url: 'Patient/12345/Observation?category=vital-signs' },
{ method: 'GET', url: 'Patient/12345/Condition?clinical-status=active' }
]);
bundle.entry.forEach((entry, index) => {
console.log(`Resposta ${index}: ${entry.response.status}`);
console.log(entry.resource);
});
Requisições Transacionais
Execute múltiplas operações de forma atômica:
const transactionRequest = async (requests) => {
const bundle = {
resourceType: 'Bundle',
type: 'transaction',
entry: requests.map(req => ({
resource: req.resource,
request: {
method: req.method,
url: req.url
}
}))
};
const response = await fhirRequest('', {
method: 'POST',
body: JSON.stringify(bundle)
});
return response;
};
// Uso - Criar paciente e condição atômica
const transaction = await transactionRequest([
{
method: 'POST',
url: 'Patient',
resource: {
resourceType: 'Patient',
name: [{ family: 'Doe', given: ['Jane'] }],
gender: 'female',
birthDate: '1990-01-01'
}
},
{
method: 'POST',
url: 'Condition',
resource: {
resourceType: 'Condition',
clinicalStatus: { coding: [{ code: 'active' }] },
code: { coding: [{ system: 'http://snomed.info/sct', code: '38341003' }] },
subject: { reference: 'Patient/-1' }
}
}
]);
Assinaturas e Webhooks
Assinaturas FHIR (R4B+)
Assine eventos de mudança:
const createSubscription = async (subscriptionData) => {
const subscription = {
resourceType: 'Subscription',
status: 'requested',
criteria: subscriptionData.criteria,
reason: subscriptionData.reason,
channel: {
type: 'rest-hook',
endpoint: subscriptionData.endpoint,
payload: 'application/fhir+json'
}
};
const response = await fhirRequest('/Subscription', {
method: 'POST',
body: JSON.stringify(subscription)
});
return response;
};
// Uso - Assinar novos resultados de laboratório
const subscription = await createSubscription({
criteria: 'DiagnosticReport?category=laboratory&patient=12345',
reason: 'Monitorar resultados de laboratório do paciente',
endpoint: 'https://myapp.com/webhooks/fhir'
});
Lidando com Webhooks FHIR
const express = require('express');
const app = express();
app.post('/webhooks/fhir', express.json({ type: 'application/fhir+json' }), async (req, res) => {
const notification = req.body;
// Verificar referência da assinatura
if (notification.subscription !== expectedSubscription) {
return res.status(401).send('Não autorizado');
}
// Processar notificação
if (notification.event?.resourceType === 'DiagnosticReport') {
const reportId = notification.event.resourceId;
const report = await fhirRequest(`/DiagnosticReport/${reportId}`);
// Processar novo resultado de laboratório
await processLabResult(report);
}
res.status(200).send('OK');
});
Solução de Problemas Comuns
Problema: 401 Não Autorizado
Sintomas: Erro “Não Autorizado” ou “Token inválido”.
Soluções:
- Verifique se o token não expirou.
- Confirme escopos do token.
- Cabeçalho
Authorization: Bearer {token}deve estar presente. - A URL FHIR deve coincidir com a audiência do token.
Problema: 403 Proibido
Sintomas: Token válido, acesso negado.
Soluções:
- Usuário tem permissão para o recurso?
- Contexto do paciente corresponde?
- Escopos SMART cobrem a operação?
- Verifique controles de acesso no recurso.
Problema: 404 Não Encontrado
Sintomas: Recurso não existe ou endpoint incorreto.
Soluções:
- ID do recurso correto?
- URL base FHIR correta?
- Tipo de recurso suportado?
- Endpoint da versão correta (R4 vs R4B)?
Problema: 422 Entidade Não Processável
Sintomas: Erros de validação ao criar/atualizar.
Debug:
// Analisar erros de validação
const error = await response.json();
error.issue?.forEach(issue => {
console.log(`Severidade: ${issue.severity}`);
console.log(`Localização: ${issue.expression?.join('.')}`);
console.log(`Mensagem: ${issue.details?.text}`);
});
Causas comuns:
- Campos obrigatórios ausentes
- Códigos inválidos
- Referência incorreta
- Formato de data inválido
Lista de Verificação para Implantação em Produção
Antes de liberar, valide:
- [ ] OAuth 2.0 + SMART on FHIR configurados
- [ ] Lógica de atualização de token
- [ ] Tratamento de erros robusto
- [ ] Logging sem PHI sensível
- [ ] Limitação de taxa
- [ ] Retentativa com backoff exponencial
- [ ] Testes com múltiplos EHRs
- [ ] Validação com FHIR Validator
- [ ] Documentação completa das operações
- [ ] Monitoramento e alertas
- [ ] Runbook para incidentes
Validação FHIR
const { FhirValidator } = require('fhir-validator');
const validator = new FhirValidator('4.0.1');
const validateResource = async (resource) => {
const validationResult = await validator.validate(resource);
if (!validationResult.valid) {
validationResult.issues.forEach(issue => {
console.error(`Erro de Validação: ${issue.message}`);
console.error(`Localização: ${issue.path}`);
});
throw new Error('Falha na validação do recurso');
}
return true;
};
// Uso antes de criar/atualizar
await validateResource(patientResource);
Casos de Uso no Mundo Real
Integração com Portal do Paciente
- Desafio: Acesso a prontuários de múltiplos provedores.
- Solução: Aplicativo SMART on FHIR integrado a Epic e Cerner.
- Resultado: 80% de adoção, 50% menos solicitações de prontuários.
Implementação:
- Lançamento SMART para paciente
- Somente leitura: Patient, Observation, Condition, MedicationRequest
- Sessão persistente via atualização de token
- UI responsiva para mobile
Suporte à Decisão Clínica
- Desafio: Perda de oportunidades de cuidados preventivos.
- Solução: Consultas FHIR em tempo real para gap de cuidados.
- Resultado: +25% nas pontuações HEDIS.
Implementação:
- App SMART para provedores
- Consulta a Patient, Condition, Observation, Immunization
- Cálculo de lacunas via guidelines
- Recomendações dentro do EHR
Análise de Saúde da População
- Desafio: Dados incompletos entre redes.
- Solução: Exportação em massa FHIR para análise.
- Resultado: Visão 360º do paciente, custos PMPM menores.
Implementação:
- Uso do FHIR Bulk Data ($export)
- Exportações noturnas para data warehouse
- Modelos de risco e alertas integrados
Conclusão
HL7 FHIR é a base para integração moderna em saúde. Para uma integração pronta para produção:
- Use FHIR R4 para APIs de saúde.
- Implemente OAuth 2.0 via SMART on FHIR.
- Modele dados com recursos padronizados.
- Utilize busca flexível e operações em lote/transação.
- Apidog agiliza testes e documentação FHIR.
Seção de Perguntas Frequentes
Para que é usado o HL7 FHIR?
Permite troca padronizada de dados de saúde entre EHRs, portais, apps mobile e sistemas de TI. Casos comuns: apps para paciente, SDS, saúde populacional, coordenação de cuidados.
Como faço para começar com o FHIR?
Acesse um servidor público (ex: HAPI FHIR) ou configure um serviço cloud (Azure, AWS). Pratique leituras e buscas de recursos.
Qual é a diferença entre HL7 v2 e FHIR?
HL7 v2 usa mensagens delimitadas (ADT, ORM, ORU); FHIR usa RESTful/JSON/XML orientado a recursos. FHIR é mais simples para web/mobile.
O FHIR é compatível com HIPAA?
Depende da implementação: criptografia, autenticação, controle de acesso, audit trail. Use OAuth 2.0 + SMART para segurança.
O que são escopos SMART?
Definem permissões granulares para recursos FHIR (ex: patient/Observation.read). Solicite apenas o necessário.
Como faço para buscar recursos no FHIR?
GET com query params: /Patient?name=Smith&birthdate=ge1980-01-01. Modificadores suportados: :exact, :contains, prefixos gt, lt, etc.
O que é FHIR em Massa?
Bulk FHIR ($export) permite exportação assíncrona de grandes conjuntos de dados em NDJSON para análise.
Como lido com o versionamento do FHIR?
Aponte para uma versão específica do FHIR (R4 recomendado) e valide via CapabilityStatement.
Posso estender o FHIR com campos personalizados?
Sim, use extensões FHIR e registre no Implementation Guide.
Quais ferramentas ajudam no desenvolvimento FHIR?
HAPI FHIR, FHIR Validator, coleções Postman e Apidog para testes/documentação.

Top comments (0)