Pacotes, composições e Transações
Introdução
Este documento técnico detalha como utilizar o recurso Bundle do FHIR (Fast Healthcare Interoperability Resources) para realizar operações em pacote (batch) e transações através das APIs da Nilo. O Bundle é um container para uma coleção de recursos relacionados. Ele pode ser usado para diversos propósitos, incluindo o agrupamento de recursos logicamente relacionados e a execução de um conjunto de operações como uma única unidade atômica (transação) ou independente (pacote).
Conceitos Fundamentais
Um Bundle é um recurso FHIR que contém uma lista de outros recursos dentro de sua propriedade entry
. Cada entrada (Bundle.entry
) possui as seguintes propriedades relevantes para pacotes e transações:
- fullUrl: Uma URI única para identificar o recurso dentro do Bundle. Isso é crucial para referenciar um recurso dentro do Bundle a partir de outro recurso no mesmo Bundle.
- resource: O próprio recurso FHIR (por exemplo,
Patient
,Condition
,CarePlan
) que está sendo incluído no Bundle. - request: Detalhes sobre a operação a ser realizada para este recurso em um cenário transacional ou em lote. Isso inclui o
method
(POST, PUT, GET, DELETE) e aurl
do endpoint do recurso. Para operações de criação, o método geralmente éPOST
e aurl
é o nome do recurso (e.g.,Patient
,Condition
). O atributoifNoneExist
pode ser utilizado com o métodoPOST
para evitar a criação de duplicados baseados em um critério de identificação.
O atributo type
do recurso Bundle define como o Bundle deve ser processado:
batch
: Indica que as operações no Bundle são independentes e podem ser processadas separadamente. Não há garantia de atomicidade.
Pacotes (Batch) de Recursos
A utilização de Bundles com o type
definido como batch
permite o envio de múltiplas operações para o servidor FHIR em uma única requisição HTTP. Cada entry
no Bundle representa uma operação individual que será processada de forma independente.
Exemplo de Pacote (Batch):
Suponha que a Acme Saúde precise criar dois novos pacientes. Podemos agrupar as operações de criação em um Bundle do tipo batch
:
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{
"fullUrl": "urn:uuid:123e4567-e89b-12d3-a456-426614174000",
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=https://servicos.receita.fazenda.gov.br/servicos/cpf/|01234567890"
},
"resource": {
"resourceType": "Patient",
"identifier": [
{
"system": "https://servicos.receita.fazenda.gov.br/servicos/cpf/",
"value": "01234567890"
}
],
"name": [
{
"use": "official",
"text": "Bugs Bunny"
}
],
"gender": "male",
"birthDate": "1940-07-27",
"telecom": [
{
"system": "email",
"value": "bugs.bunny@acmesaude.com.br",
"use": "work"
}
]
}
},
{
"fullUrl": "urn:uuid:987f6543-ba09-87dc-5678-0987654321ab",
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=https://servicos.receita.fazenda.gov.br/servicos/cpf/|98765432109"
},
"resource": {
"resourceType": "Patient",
"identifier": [
{
"system": "https://servicos.receita.fazenda.gov.br/servicos/cpf/",
"value": "98765432109"
}
],
"name": [
{
"use": "official",
"text": "Lola Bunny"
}
],
"gender": "female",
"birthDate": "1996-04-03",
"telecom": [
{
"system": "email",
"value": "lola.bunny@acmesaude.com.br",
"use": "work"
}
]
}
}
]
}
Ao enviar este Bundle com type batch, o servidor FHIR tentará criar ambos os recursos Patient de forma independente. O resultado da requisição conterá um Bundle de resposta com o status de cada operação.
Transações com Bundle
Uma outra maneira de usar pacotes é usar referências internas. A principal diferença é que o recurso que faz a referência quando for processado seja automaticamente
associado pelo sistema ao recurso referenciado criado, já com a referência correta para o identifier
desse novo recurso.
É uma maneira prática de criar num mesmo request dois recursos diferentes e já fazer a associação entre eles.
Exemplo de Transação:
A Acme Saúde precisa registrar um novo paciente e associar uma condição médica a ele em um único pacote.
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{
"fullUrl": "urn:uuid:c0ffee00-c0de-cafe-babe-deadbeef0001",
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=https://servicos.receita.fazenda.gov.br/servicos/cpf/|13579086420"
},
"resource": {
"resourceType": "Patient",
"identifier": [
{
"system": "https://servicos.receita.fazenda.gov.br/servicos/cpf/",
"value": "13579086420"
}
],
"name": [
{
"use": "official",
"text": "Piu-Piu Silva"
}
],
"gender": "male",
"birthDate": "2010-05-05",
"telecom": [
{
"system": "email",
"value": "piu-piu.silva@acmesaude.com.br",
"use": "home"
}
]
}
},
{
"request": {
"method": "POST",
"url": "Condition"
},
"fullUrl": "urn:uuid:c0ffee00-c0de-cafe-babe-deadbeef0002",
"resource": {
"resourceType": "Condition",
"subject": {
"reference": "urn:uuid:c0ffee00-c0de-cafe-babe-deadbeef0001"
},
"code": {
"coding": [
{
"code": "K59.0",
"display": "Constipação",
"system": "http://hl7.org/fhir/sid/icd-10"
}
]
},
"verificationStatus": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/condition-ver-status",
"code": "confirmed"
}
]
}
}
}
]
}
Neste exemplo de pacote:
- Um recurso Patient é criado com um
fullUrl
único (urn:uuid:c0ffee00-c0de-cafe-babe-deadbeef0001
). O blocorequest
especifica um POST para o endpoint Patient. OifNoneExist
garante que um novo paciente só será criado se não existir um com o CPF especificado. - Um recurso Condition é criado e referencia o Patient recém-criado utilizando seu
fullUrl
no atributosubject.reference
. O bloco request especifica um POST para o endpoint Condition.
Ao enviar este Bundle com referência interna, o servidor FHIR processará as operações sequencialmente. Se a criação do Patient for bem-sucedida, mas houver um erro ao criar a Condition, o Patient será criado, mas um erro indicará que não houve sucesso na criação da Condition.
Na resposta, virá um detalhamento com a referencia ao recurso pelo fullUrl
e o erro, e os recursos criados com sucesso terão sua referencia feita pelo id.
Usando como base o exemplo acima, o retorno para o caso do paciente ser criado mas a condição de saúde não, seria:
{
"entry": [
{
"response": {
"location": "urn:uuid:c0ffee00-c0de-cafe-babe-deadbeef0002",
"outcome": {
"issue": [
{
"code": "structure",
"details": {
"text": "Resource dependencies not processed successfully"
},
"expression": [
"Bundle.entry"
],
"severity": "error"
}
],
"resourceType": "OperationOutcome"
},
"status": "400 Bad Request"
}
},
{
"response": {
"location": "Patient/fc192bbb-4970-4943-989f-586e63859985",
"status": "200 OK"
}
}
]
}
Considerações para Desenvolvedores
- Identificadores: É fundamental utilizar identificadores únicos (identifier e fullUrl) de forma consistente dentro do Bundle para garantir referências corretas entre os recursos.
- Referências: Ao referenciar recursos dentro do mesmo Bundle, utilize o fullUrl do recurso de destino. Para referenciar recursos existentes fora do Bundle, utilize um identificador(
identifier
) do recurso. - Tratamento de Erros: Ao realizar transações e operações em pacote, implemente mecanismos robustos para lidar com as respostas da API. Para Bundles cada entry na resposta conterá o resultado da operação individual.
- Performance: Embora os Bundles possam otimizar o número de requisições para a API, Bundles muito grandes podem impactar a performance do sistema. Considere o tamanho e a complexidade dos Bundles ao projetar suas integrações. Recomendamos não enviar mais que 10 recursos num mesmo Bundle, idealmente, se possível, ficar em torno de 5.
- Documentação da API: Consulte sempre a documentação oficial da API da Nilo (https://docs.nilo.services/docs/category/apis-fhir) e a especificação FHIR R4 (https://hl7.org/fhir/R4/index.html) para obter detalhes específicos sobre o suporte a Bundles e quaisquer requisitos ou limitações adicionais.
A utilização eficiente de Bundles para operações em pacote e transações permite que sejam realizadas integrações mais complexas e consistentes com outros sistemas de saúde, aproveitando ao máximo os padrões de interoperabilidade do FHIR