Como Usar a API HL7 FHIR: Guia Completo de Integração em Saúde (2026)

Ashley Innocent

Ashley Innocent

25 março 2026

Como Usar a API HL7 FHIR: Guia Completo de Integração em Saúde (2026)

Apidog para empresas

Implantação local

SSO & RBAC

Conforme SOC 2

Explorar Apidog Enterprise

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.

Introdução

A fragmentação dos dados de saúde custa ao sistema de saúde dos EUA US$ 30 bilhões anualmente. Para desenvolvedores que constroem aplicativos de saúde, a integração da API HL7 FHIR não é opcional — é o padrão da indústria exigido pelo CMS e adotado pela Epic, Cerner e todos os principais fornecedores de EHR.

Aqui está a realidade: provedores que usam aplicativos habilitados para FHIR reduzem o tempo de coordenação de cuidados em 40% e eliminam 85% das solicitações de prontuários baseadas em fax. Uma integração sólida da API FHIR permite a troca contínua de dados entre EHRs, portais de pacientes e plataformas de coordenação de cuidados.

Este guia aborda o processo completo de integração da API HL7 FHIR. Você aprenderá sobre a arquitetura FHIR, tipos de recursos, parâmetros de busca, autenticação OAuth 2.0, integração SMART on FHIR e estratégias de implantação em produção. Ao final, você terá uma integração FHIR pronta para produção.

💡
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.
botão

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 usa tecnologias web modernas, incluindo APIs RESTful, JSON, XML e OAuth 2.0.

Tipos de recursos FHIR mais usados

Tipos de Recursos FHIR

FHIR define mais de 140 tipos de recursos. Os recursos centrais incluem:

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

FHIR usa uma estrutura de API 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 que os EHRs Certificados suportem o FHIR R4 para APIs de Acesso ao Paciente e Acesso ao Provedor.

Primeiros Passos: Acesso ao Servidor FHIR

Passo 1: Escolha Seu Servidor FHIR

Opções para implantação de servidor FHIR:

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

Para serviços FHIR na nuvem:

# 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

FHIR suporta métodos HTTP padrão:

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();

  // Adicionar parâmetros de busca
  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, // ex.: '8480-6' para Pressão Arterial Sistólica
        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 à lista de problemas:

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

Servidores FHIR usam OAuth 2.0 com 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

Implementar o lançamento de aplicativo SMART:

const crypto = require('crypto');

class SMARTClient {
  constructor(config) {
    this.clientId = config.clientId;
    this.redirectUri = config.redirectUri;
    this.issuer = config.issuer; // URL do servidor FHIR
    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();

    // Armazenar codeVerifier para troca de token
    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 múltiplas requisições independentes:

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 requisições como uma unidade 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 recursos relacionados
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' } // Referência ao primeiro recurso
    }
  }
]);

Assinaturas e Webhooks

Assinaturas FHIR (R4B+)

Assine as mudanças de recurso:

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: Recebendo erros de “Não Autorizado” ou “Token inválido”.

Soluções:

  1. Verifique se o token não expirou
  2. Verifique se o escopo do token inclui o recurso solicitado
  3. Certifique-se de que o cabeçalho Authorization: Bearer {token} esteja presente
  4. Verifique se a URL do servidor FHIR corresponde à audiência do token

Problema: 403 Proibido

Sintomas: O token é válido, mas o acesso é negado.

Soluções:

  1. Verifique se o usuário tem permissão para o recurso solicitado
  2. Verifique se o contexto do paciente corresponde (para tokens com escopo de paciente)
  3. Certifique-se de que os escopos SMART incluam a operação solicitada
  4. Verifique os controles de acesso no nível do recurso

Problema: 404 Não Encontrado

Sintomas: O recurso não existe ou o endpoint está incorreto.

Soluções:

  1. Verifique se o ID do recurso está correto
  2. Verifique se a URL base do FHIR está correta
  3. Certifique-se de que o tipo de recurso é suportado pelo servidor
  4. Verifique o endpoint específico da versão (R4 vs R4B)

Problema: 422 Entidade Não Processável

Sintomas: Erros de validação ao criar/atualizar.

Soluções:

// 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:

Lista de Verificação para Implantação em Produção

Antes de entrar em produção:

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

Um sistema de saúde constrói um portal do paciente:

Implementação chave:

Suporte à Decisão Clínica

Uma plataforma de gerenciamento de cuidados adiciona SDS:

Implementação chave:

Análise de Saúde da População

Uma operadora de saúde constrói um painel de saúde da população:

Implementação chave:

Conclusão

HL7 FHIR fornece a base para a interoperabilidade moderna na saúde. Principais pontos:

botão

Seção de Perguntas Frequentes

Para que é usado o HL7 FHIR?

FHIR permite a troca padronizada de dados de saúde entre EHRs, portais de pacientes, aplicativos móveis e outros sistemas de TI de saúde. Casos de uso comuns incluem aplicativos de acesso ao paciente, suporte à decisão clínica, saúde da população e coordenação de cuidados.

Como faço para começar com o FHIR?

Comece acessando um servidor FHIR público (como o servidor de teste HAPI FHIR) ou configure um serviço FHIR na nuvem (Azure API for FHIR, AWS HealthLake). Pratique a leitura de recursos e o uso de parâmetros de busca.

Qual é a diferença entre HL7 v2 e FHIR?

HL7 v2 usa mensagens delimitadas por pipes (ADT, ORM, ORU) para troca de dados orientada a eventos. FHIR usa APIs RESTful com JSON/XML para acesso baseado em recursos. FHIR é mais fácil de implementar e mais adequado para aplicativos web/mobile modernos.

O FHIR é compatível com HIPAA?

FHIR é um padrão de formato de dados. A conformidade com HIPAA depende da implementação: criptografia, autenticação, controles de acesso e registro de auditoria. Use OAuth 2.0 com SMART on FHIR para acesso seguro.

O que são escopos SMART?

Os escopos SMART definem permissões de acesso granulares para recursos FHIR (por exemplo, patient/Observation.read, user/*.read). Solicite apenas os escopos que seu aplicativo precisa.

Como faço para buscar recursos no FHIR?

Use requisições GET com parâmetros de consulta: /Patient?name=Smith&birthdate=ge1980-01-01. FHIR suporta modificadores (:exact, :contains) e prefixos (gt, lt, ge, le).

O que é FHIR em Massa?

FHIR em Massa ($export) permite a exportação assíncrona de grandes conjuntos de dados no formato NDJSON. Usado para saúde da população, análise e armazenamento de dados.

Como lido com o versionamento do FHIR?

Direcione uma versão específica do FHIR (R4 recomendado) e use endpoints específicos da versão. Verifique o CapabilityStatement para as versões e recursos suportados.

Posso estender o FHIR com campos personalizados?

Sim, use extensões FHIR para adicionar elementos de dados personalizados. Defina as extensões em seu Guia de Implementação e registre-as no HL7 se for compartilhar amplamente.

Quais ferramentas ajudam no desenvolvimento FHIR?

Ferramentas populares incluem HAPI FHIR (servidor de código aberto), validador FHIR, coleções Postman e Apidog para teste e documentação de API.

Pratique o design de API no Apidog

Descubra uma forma mais fácil de construir e usar APIs