Controlar el acceso a los recursos de FHIR en la API Cloud Healthcare

En esta página se describe cómo usar los recursos Consent de FHIR para determinar el acceso a los datos de los almacenes FHIR en la API Cloud Healthcare.

Para configurar un almacén FHIR con la opción de aplicar el consentimiento, sigue estos pasos:

  1. Crea un almacén FHIR si aún no tienes uno.

  2. Defina los siguientes parámetros ConsentConfig del almacén FHIR para habilitar la aplicación del consentimiento:

    • version: especifica qué versión de la aplicación del consentimiento se está usando en el almacén FHIR. Este valor solo se puede definir una vez mediante CreateFhirStore o UpdateFhirStore. Una vez que lo hayas configurado, debes llamar al ApplyConsents o al ApplyAdminConsents para cambiar la versión.

    • access_enforced: si se le asigna el valor true, al acceder a los recursos FHIR, los encabezados de consentimiento proporcionados se verificarán con las directivas de consentimiento dadas por los consumidores.

    • consent_header_handling: Si se define como PERMIT_EMPTY_SCOPE (valor predeterminado), el servidor permite solicitudes sin encabezado X-Consent-Scope (o con un encabezado vacío). Si se define como REQUIRED_ON_READ y access_enforced = true, el servidor rechaza todas las solicitudes sin el encabezado X-Consent-Scope (o con él vacío).

Configurar un almacén FHIR con ConsentConfig

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    --data "{
      'version': 'R4',
      'enableUpdateCreate': true,
      'consentConfig': {
        'version': 'V1',
        'accessEnforced': true
      }
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores?fhirStoreId=FHIR_STORE_ID"

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID",
  "version": "R4",
  "enableUpdateCreate": true,
  "consentConfig": {
    "version": "V1"
  }
}

Si ya tienes una tienda, usa UpdateFhirStore para definir el ConsentConfig con la opción de cumplimiento del consentimiento version como V1 y define accessEnforced como true.

curl -X PATCH \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    --data "{
      'consentConfig': {
        'version': 'V1',
        'accessEnforced': true
      }
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID?update_mask=consentConfig"

Las políticas se representan mediante el recurso Consent. El propósito y el uso de los campos de recursos se describen en la documentación del modelo de datos.

A continuación se muestra un ejemplo de todos los recursos que se pueden crear en este caso concreto.

Crear recursos FHIR

En el siguiente ejemplo se muestra cómo ejecutar un [paquete FHIR](/healthcare-api/docs/how-tos/fhir-bundles) para rellenar los siguientes recursos:

  • Un recurso Practitioner con el nombre Jeffrey Brown
  • Un recurso Patient con el nombre Darcy Smith
  • Recurso Observation que muestra la medición de hemoglobina de Darcy (LOINC718-7) recogida por el Happy Hospital
  • Recurso Observation que muestra la medición de glucosa de Darcy (LOINC15074-8).
  • Consentimiento de Darcy para permitir que Jeffrey Brown use la aplicación App/123 para acceder a sus datos recogidos por Happy Hospital
  • Consentimiento de Darcy para permitir que Jeffrey Brown acceda a cualquiera de sus datos para tratamiento de emergencia (ETREAT)
  • Un consentimiento del Happy Hospital para permitir que Jeffrey Brown acceda a todos los datos cuando realice investigaciones biomédicas (BIORCH) con la aplicación App/golden

cat > bundle.json << 'EOF'
{
  "resourceType": "Bundle",
  "type": "transaction",
  "entry": [
    {
      "request": {"method": "PUT", "url": "Practitioner/12942879-f89f-41ae-aa80-0b911b649833"},
      "resource": {
        "active": true,
        "birthDate": "1970-05-23",
        "gender": "male",
        "id": "12942879-f89f-41ae-aa80-0b911b649833",
        "name": [{
            "family": "Brown",
            "given": ["Jeffrey"],
            "use": "official"
        }],
        "resourceType": "Practitioner"
      }
    },
    {
      "request": {"method": "PUT", "url": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"},
      "resource": {
        "active": true,
        "birthDate": "1990-01-01",
        "gender": "female",
        "id": "3c6aa096-c054-4c22-b2b4-1e4a4d203de2",
        "name": [{
            "family": "Smith",
            "given": ["Darcy"],
            "use": "official"
        }],
        "meta": {
          "tag": [{
            "system": "http://terminology.hl7.org/CodeSystem/common-tags",
            "code": "employee"
          }]
        },
        "resourceType": "Patient"
      }
    },
    {
      "request": {"method": "PUT", "url": "Observation/7473784b-46a8-470c-b9a6-fe38a01025aa"},
      "resource": {
        "id": "7473784b-46a8-470c-b9a6-fe38a01025aa",
        "meta": {"source": "http://example.com/HappyHospital"},
        "code": {
          "coding": [{
            "code": "718-7",
            "system": "http://loinc.org",
            "display": "Hemoglobin [Mass/volume] in Blood"
          }]
        },
        "effectivePeriod": {"start": "2021-12-10T05:30:10+01:00"},
        "issued": "2021-12-10T13:30:10+01:00",
        "resourceType": "Observation",
        "status": "final",
        "subject": {"reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"},
        "valueQuantity": {
          "code": "g/dL",
          "system": "http://unitsofmeasure.org",
          "unit": "g/dl",
          "value": 7.2
        }
      }
    },
    {
      "request": {"method": "PUT", "url": "Observation/68583624-9921-4158-8754-2a306c689abd"},
      "resource": {
        "id": "68583624-9921-4158-8754-2a306c689abd",
        "code": {
          "coding": [{
            "code": "15074-8",
            "system": "http://loinc.org",
            "display": "Glucose [Moles/volume] in Blood"
          }]
        },
        "effectivePeriod": {"start": "2021-12-01T05:30:10+01:00"},
        "issued": "2021-12-01T13:30:10+01:00",
        "resourceType": "Observation",
        "status": "final",
        "subject": {"reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"},
        "valueQuantity": {
          "code": "mmol/L",
          "system": "http://unitsofmeasure.org",
          "unit": "mmol/l",
          "value": 6.3
        }
      }
    },
    {
      "request": {"method": "PUT", "url": "Consent/10998b60-a252-405f-aa47-0702554ddc8e"},
      "resource": {
        "category": [{
          "coding": [{
            "code": "59284-0",
            "system": "http://terminology.hl7.org/CodeSystem/consentcategorycodes"
          }]
        }],
        "id": "10998b60-a252-405f-aa47-0702554ddc8e",
        "patient": {"reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"},
        "policyRule": {
          "coding": [{
            "code": "OPTIN",
            "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
          }]
        },
        "provision": {
          "actor": [
            {
              "reference": {"reference": "Practitioner/12942879-f89f-41ae-aa80-0b911b649833"},
              "role": {
                "coding": [{
                  "code": "GRANTEE",
                  "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode"
                }]
              }
            }
          ],
          "extension": [
            {
              "url": "https://g.co/fhir/medicalrecords/Environment",
              "valueCodeableConcept": {
                "coding": [{
                  "code": "123",
                  "system": "App"
                }]
              }
            },
            {
              "url": "https://g.co/fhir/medicalrecords/DataSource",
              "valueUri": "http://example.com/HappyHospital"
            }
          ],
          "type": "permit"
        },
        "resourceType": "Consent",
        "scope": {
          "coding": [{
            "code": "patient-privacy",
            "system": "http://terminology.hl7.org/CodeSystem/consentscope"
          }]
        },
        "status": "active"
      }
    },
    {
      "request": {"method": "PUT", "url": "Consent/73c54e8d-2789-403b-9dee-13085c5d5e34"},
      "resource": {
        "category": [{
          "coding": [{
            "code": "59284-0",
            "system": "http://terminology.hl7.org/CodeSystem/consentcategorycodes"
          }]
        }],
        "id": "73c54e8d-2789-403b-9dee-13085c5d5e34",
        "patient": {"reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"},
        "policyRule": {
          "coding": [{
            "code": "OPTIN",
            "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
          }]
        },
        "provision": {
          "actor": [
            {
              "reference": {"reference": "Practitioner/12942879-f89f-41ae-aa80-0b911b649833"},
              "role": {
                "coding": [{
                  "code": "GRANTEE",
                  "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode"
                }]
              }
            }
          ],
          "purpose": [{
            "code": "ETREAT",
            "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason"
          }],
          "type": "permit"
        },
        "resourceType": "Consent",
        "scope": {
          "coding": [{
            "code": "patient-privacy",
            "system": "http://terminology.hl7.org/CodeSystem/consentscope"
          }]
        },
        "status": "active"
      }
    },
    {
      "request": {"method": "PUT", "url": "Consent/5c8e3f8a-9fd5-480d-a08e-f29b89feccde"},
      "resource": {
        "category": [{
          "coding": [{
            "code": "57017-6",
            "system": "http://loinc.org"
          }]
        }],
        "id": "5c8e3f8a-9fd5-480d-a08e-f29b89feccde",
        "patient": {},
        "extension": [{
          "url": "https://g.co/fhir/medicalrecords/ConsentAdminPolicy"
        }],
        "policyRule": {
          "coding": [{
            "code": "OPTIN",
            "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
          }]
        },
        "provision": {
          "actor": [
            {
              "reference": {"reference": "Practitioner/12942879-f89f-41ae-aa80-0b911b649833"},
              "role": {
                "coding": [{
                  "code": "GRANTEE",
                  "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode"
                }]
              }
            }
          ],
          "purpose": [{
            "code": "BIORCH",
            "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason"
          }],
          "extension": [
            {
              "url": "https://g.co/fhir/medicalrecords/Environment",
              "valueCodeableConcept": {
                "coding": [{
                  "code": "golden",
                  "system": "App"
                }]
              }
            }
          ],
          "type": "permit"
        },
        "resourceType": "Consent",
        "scope": {},
        "status": "active"
      }
    }
  ]
}
EOF
curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/fhir+json; charset=utf-8" \
    --data @bundle.json \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir"

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "entry": [
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner/12942879-f89f-41ae-aa80-0b911b649833/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/68583624-9921-4158-8754-2a306c689abd/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/10998b60-a252-405f-aa47-0702554ddc8e/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/73c54e8d-2789-403b-9dee-13085c5d5e34/_history/VERSION_ID",
        "status": "201 Created"
      }
    },
    {
      "response": {
        "etag": "W/\"VERSION_ID\"",
        "lastModified": "2022-09-01T17:31:40.423469+00:00",
        "location": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/5c8e3f8a-9fd5-480d-a08e-f29b89feccde/_history/VERSION_ID",
        "status": "201 Created"
      }
    }
  ],
  "resourceType": "Bundle",
  "type": "transaction-response"
}

A continuación se incluyen más ejemplos de recursos Consent de R4 que muestran cómo se pueden representar políticas complejas.

{
  "resourceType": "Consent",
  "id": "patient-consent-example",
  "patient": {
    "reference": "Patient/f001"
  },
  "category": [
    {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59284-0"
        }
      ]
    }
  ],
  "scope": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/consentscope",
        "code": "patient-privacy"
      }
    ]
  },
  "policyRule": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "OPTIN"
      }
    ]
  },
  "status": "active",
  "provision": {
    "type": "permit",
    "actor": [
      {
        "reference": {
          "reference": "Practitioner/f002"
        },
        "role": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
              "code": "GRANTEE"
            }
          ]
        }
      }
    ],
    "purpose": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
        "code": "TREAT"
      }
    ],
    "class": [
      {
        "system": "http://hl7.org/fhir/resource-types",
        "code": "Encounter"
      }
    ],
    "data": [
      {
        "meaning": "instance",
        "reference": {
          "reference": "Encounter/e001"
        }
      }
    ],
    "extension": [
      {
        "url": "https://g.co/fhir/medicalrecords/Environment",
        "valueCodeableConcept": {
          "coding": [
            {
              "system": "iso3166-1",
              "code": "CA"
            }
          ]
        }
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataTag",
        "valueCoding": {
          "system": "http://terminology.hl7.org/CodeSystem/common-tags",
          "code": "actionable"
        }
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataTag",
        "extension": [
          {
            "url": "https://g.co/fhir/medicalrecords/DataTag",
            "valueCoding": {
              "system": "http://example.com/custom-tags",
              "code": "archived"
            }
          },
          {
            "url": "https://g.co/fhir/medicalrecords/DataTag",
            "valueCoding": {
              "system": "http://example.com/custom-tags",
              "code": "insensitive"
            }
          }
        ]
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataSource",
        "valueUri": "http://somesystem.example.org/foo"
      }
    ],
    "securityLabel": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality",
        "code": "R"
      },
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "PSY"
      }
    ]
  }
}

El ejemplo anterior representa un recurso Consent de un paciente en el que un paciente f001 da permiso a un profesional sanitario f002 con el fin de recibir un tratamiento periódico representado por TREAT. El profesional procede de la geolocalización iso3166-1/CA. Este recurso Consent permite al profesional acceder a los datos del paciente si los datos cumplen todas las condiciones siguientes.

  • Es de tipo Encounter y tiene el ID Encounter/e001.
  • Procede de la fuente http://somesystem.example.org/foo.
  • Cumple al menos una de las siguientes condiciones en la etiqueta (los recursos se pueden etiquetar configurando los campos system y code de Meta.tags):
    • Tiene la etiqueta (system = http://terminology.hl7.org/CodeSystem/common-tags y code = actionable)
    • Tiene ambas etiquetas (system = http://example.com/custom-tags y code = archived) and (system = http://example.com/custom-tags y code = insensitive)
  • Tiene al menos una de las siguientes etiquetas de seguridad
    • system = http://terminology.hl7.org/CodeSystem/v3-Confidentiality y code es uno de los siguientes valores: R, N, M, L o U.
    • system = http://terminology.hl7.org/CodeSystem/v3-ActCode y code = PSY.

Directiva de política de administrador de ejemplo

{
  "resourceType": "Consent",
  "id": "admin-policy-example",
  "patient": {},
  "extension": [{
    "url": "https://g.co/fhir/medicalrecords/ConsentAdminPolicy"
  }],
  "category": [
    {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "57017-6"
        }
      ]
    }
  ],
  "scope": {},
  "policyRule": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "OPTIN"
      }
    ]
  },
  "status": "active",
  "provision": {
    "type": "permit",
    "actor": [
      {
        "reference": {
          "reference": "Practitioner/f002"
        },
        "role": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
              "code": "GRANTEE"
            }
          ]
        }
      }
    ],
    "purpose": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
        "code": "TREAT"
      }
    ],
    "class": [
      {
        "system": "http://hl7.org/fhir/resource-types",
        "code": "Encounter"
      }
    ],
    "data": [
      {
        "meaning": "instance",
        "reference": {
          "reference": "Encounter/e001"
        }
      }
    ],
    "extension": [
      {
        "url": "https://g.co/fhir/medicalrecords/Environment",
        "valueCodeableConcept": {
          "coding": [
            {
              "system": "iso3166-1",
              "code": "CA"
            }
          ]
        }
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataTag",
        "valueCoding": {
          "system": "http://terminology.hl7.org/CodeSystem/common-tags",
          "code": "actionable"
        }
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataTag",
        "extension": [
          {
            "url": "https://g.co/fhir/medicalrecords/DataTag",
            "valueCoding": {
              "system": "http://example.com/custom-tags",
              "code": "archived"
            }
          },
          {
            "url": "https://g.co/fhir/medicalrecords/DataTag",
            "valueCoding": {
              "system": "http://example.com/custom-tags",
              "code": "insensitive"
            }
          }
        ]
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataSource",
        "valueUri": "http://somesystem.example.org/foo"
      }
    ],
    "securityLabel": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-Confidentiality",
        "code": "R"
      },
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "PSY"
      }
    ]
  }
}

En el ejemplo anterior, el recurso Consent de la política de administrador otorga permiso a un profesional sanitario f002 con el fin de proporcionar un tratamiento periódico representado por TREAT. El profesional es de la geolocalización iso3166-1/CA. Este recurso Consent permite al profesional acceder a los datos del paciente si estos cumplen todas las condiciones siguientes:

  • Es de tipo Encounter y tiene el ID Encounter/e001.
  • Procede de la fuente http://somesystem.example.org/foo.
  • Cumple al menos una de las siguientes condiciones en la etiqueta:
    • Tiene la etiqueta (system = http://terminology.hl7.org/CodeSystem/common-tags y code = actionable)
    • Tiene ambas etiquetas (system = http://example.com/custom-tags y code = archived) and (system = http://example.com/custom-tags y code = insensitive)
  • Tiene al menos una de las siguientes etiquetas de seguridad
    • system = http://terminology.hl7.org/CodeSystem/v3-Confidentiality y code es uno de los siguientes valores: R, N, M, L o U.
    • system = http://terminology.hl7.org/CodeSystem/v3-ActCode y code = PSY.

Directiva de política en cascada de administrador de ejemplo

{
  "resourceType": "Consent",
  "id": "admin-cascading-policy-example",
  "patient": {},
  "extension": [
    { "url": "https://g.co/fhir/medicalrecords/ConsentAdminPolicy" },
    { "url": "https://g.co/fhir/medicalrecords/CascadingPolicy" }
  ],
  "category": [
    {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "57017-6"
        }
      ]
    }
  ],
  "scope": {},
  "policyRule": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "OPTIN"
      }
    ]
  },
  "status": "active",
  "provision": {
    "type": "permit",
    "actor": [
      {
        "reference": {
          "reference": "Practitioner/f002"
        },
        "role": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode",
              "code": "GRANTEE"
            }
          ]
        }
      }
    ],
    "purpose": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
        "code": "TREAT"
      }
    ],
    "class": [
      {
        "system": "http://hl7.org/fhir/resource-types",
        "code": "Patient"
      }
    ],
    "extension": [
      {
        "url": "https://g.co/fhir/medicalrecords/Environment",
        "valueCodeableConcept": {
          "coding": [
            {
              "system": "iso3166-1",
              "code": "CA"
            }
          ]
        }
      },
      {
        "url": "https://g.co/fhir/medicalrecords/DataTag",
        "valueCoding": {
          "system": "http://terminology.hl7.org/CodeSystem/common-tags",
          "code": "employee"
        }
      }
    ]
  }
}

En el ejemplo anterior se representa un recurso Consent de una política en cascada de administrador que otorga permiso a un profesional sanitario f002 con el fin de proporcionar un tratamiento habitual representado por TREAT. El profesional procede de la geolocalización iso3166-1/CA. Este recurso Consent permite al profesional acceder a los datos del compartimento de los pacientes con la etiqueta employee. Todos los criterios de recursos solo se aplican a los recursos base del compartimento, es decir, al recurso Paciente, ya que controla los recursos de los que se va a hacer una cascada.

Aplicar los consentimientos de los pacientes o las políticas de administrador

Cumplir los consentimientos de los pacientes mediante ApplyConsents

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    --data "{'validateOnly': false}" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:applyConsents"

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para hacer un seguimiento del estado de la operación, puedes usar el [método `get` de Operation](/healthcare-api/docs/reference/rest/v1/projects.locations.datasets.operations/get):

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

Cuando finaliza la operación, el servidor devuelve una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirStoreService.ApplyConsents",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "2",
      "secondarySuccess": "5"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.ApplyConsentsResponse",
    "consentApplySuccess": "2",
    "affectedResources": "5"
  }
}

Esta respuesta indica que el servidor ha procesado correctamente 2 consentimientos y ha actualizado el acceso consensual de 5 recursos (1 Patient, 2 Consents y 2 Observations).

Aplica la política de administrador ApplyAdminConsents

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json" \
    --data "{
      'validateOnly': false,
      'newConsentsList': {
        'names': ['projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/5c8e3f8a-9fd5-480d-a08e-f29b89feccde/_history/VERSION_ID']
      }
    }" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:applyAdminConsents"

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

La respuesta contiene un nombre de operación. Para hacer un seguimiento del estado de la operación, puedes usar el [método `get` de Operation](/healthcare-api/docs/reference/rest/v1/projects.locations.datasets.operations/get):

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

Cuando finaliza la operación, el servidor devuelve una respuesta con el estado de la operación en formato JSON:

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirStoreService.ApplyAdminConsents",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "1",
      "secondarySuccess": "7"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.ApplyAdminConsentsResponse",
    "consentApplySuccess": "1",
    "affectedResources": "7"
  }
}

Esta respuesta indica que el servidor ha procesado correctamente una política de administrador y ha actualizado el acceso consensual de siete recursos (un profesional sanitario, un paciente, dos observaciones, dos consentimientos de pacientes y una política de administrador).

La aplicación de los consentimientos almacenados en un almacén FHIR no entrará en vigor hasta que se llame a ApplyConsents (para los consentimientos de los pacientes) o a ApplyAdminConsents (para las políticas de administrador y las políticas de administrador en cascada) y se complete correctamente. Si añades, modificas o quitas consentimientos después de haber ejecutado ApplyConsents o ApplyAdminConsents, debes volver a ejecutarlo para que esos consentimientos se incluyan en el modelo de cumplimiento.

Los recursos FHIR se indexan de forma asíncrona, por lo que puede haber un ligero retraso entre el momento en que se completan las solicitudes ApplyConsents o ApplyAdminConsents y el momento en que el modelo de aplicación se refleja en los resultados de búsqueda. Este retraso solo se espera en las solicitudes de búsqueda.

Si es la primera vez que configuras la aplicación del consentimiento en el almacén FHIR, espera a que se complete la operación de larga duración ApplyConsents o ApplyAdminConsents antes de hacer solicitudes que tengan en cuenta el consentimiento.

Para llamar a ApplyConsents en un subconjunto de pacientes, puedes usar los siguientes filtros:

  • PatientScope: para ejecutar ApplyConsents en una lista de IDs de pacientes con hasta 10.000 pacientes

  • TimeRange: para ejecutar ApplyConsent en una lista de IDs de recursos de Patient cuyos recursos de Consent se actualizan durante un periodo determinado.

Para llamar a ApplyAdminConsents, debe proporcionar la lista completa de todas las políticas que quiera aplicar (no una lista incremental). Por lo tanto, si se incluye una lista vacía, no se aplicarán las políticas de administrador de la tienda. Cada política debe ser un nombre de versión de recurso si el almacén FHIR usa versiones y un nombre de recurso en caso contrario.

Puedes usar operations.get para obtener el ProgressCounter de la operación. Una vez completado, se incluye un ApplyConsentsResponse en el Operation.response. Los contadores de ProgressCounter y ApplyConsentsResponse o ApplyAdminConsentsResponse se describen en la siguiente tabla.

ProgressCounter ApplyConsentsResponse o ApplyAdminConsentsResponse Descripción
success consentApplySuccess Número de recursos Consent que la operación ha procesado correctamente.
failure consentApplyFailure Número de recursos Consent no admitidos o no válidos. Puedes consultar los registros de errores en Cloud Logging o, si validateOnly está false, comprobar el estado de la aplicación del consentimiento con CheckConsentEnforcementStatus o CheckPatientConsentEnforcementStatus para obtener información detallada sobre los errores.
secondarySuccess affectedResources Cuando validateOnly es false, representa el número de recursos FHIR que se han reindexado correctamente debido al efecto del cambio de consentimiento.
secondaryFailure failedResources Cuando validateOnly es false, representa el número de recursos FHIR cuyo consentimiento puede haber cambiado, pero no se han podido reindexar. Esto puede afectar a la búsqueda con contexto de consentimiento, pero no a otros métodos. Para ver los detalles del error, puedes consultar los registros de errores en Cloud Logging.

Cuando se procesan los recursos de consentimiento de FHIR, puede usar las siguientes APIs para comprobar el estado de la aplicación de un consentimiento o de todos los consentimientos de un paciente:

En el caso de las políticas de administrador, CheckConsentEnforcementStatus solo se puede usar para comprobar el estado de implementación de una única política de administrador de consentimiento. También puede usar fhirStores.get para ver todas las políticas de administrador activas aplicadas a la tienda.

El consent-enforcement-status puede tener cualquiera de los siguientes valores:

  • OFF: representa el estado de cumplimiento predeterminado de un nuevo recurso Consent en el que nunca se ha procesado el recurso Consent.

  • ENFORCEABLE: el estado en el que se ha procesado correctamente el recurso Consent.

  • INACTIVE: estado inactivo en el que se ignora el recurso Consent.

  • UNSUPPORTED: el estado de un recurso Consent que puede ajustarse a las especificaciones de FHIR, pero no se puede aplicar. Esto se debe a la implementación limitada de la aplicación del consentimiento de FHIR con el nivel actual de compatibilidad de funciones.

  • ENFORCEMENT_LIMIT_EXCEEDED: el estado en el que el formato del recurso de consentimiento de FHIR y el nivel de asistencia del recurso no tienen errores, pero se cumple una o varias de las siguientes condiciones:

    • El paciente tiene un gran conjunto de recursos Consent.

    • El tamaño de las directivas de consentimiento de todos los consentimientos activos es mayor que el tamaño máximo permitido de las directivas de consentimiento para que un servidor FHIR las aplique.

La API Cloud Healthcare admite búsquedas de recursos FHIR en un almacén FHIR determinado con actor, purpose y environment como parámetros de consulta. La respuesta solo contiene los recursos para los que se ha obtenido el consentimiento.

  1. El profesional sanitario Jeffrey Brown (identificado con Practitioner/12942879-f89f-41ae-aa80-0b911b649833) usa una aplicación de confianza App/123 y busca todas las Observations con status=final.
  2. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 env/App/123" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation?status=final"

    Deberías recibir una respuesta JSON similar a la siguiente:

    {
      "entry": [
        {
          "fullUrl": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION_ID/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa",
          "resource": {
            "code": {
              "coding": [
                {
                  "code": "718-7",
                  "display": "Hemoglobin [Mass/volume] in Blood",
                  "system": "http://loinc.org"
                }
              ]
            },
            "effectivePeriod": {
              "start": "2021-12-10T05:30:10+01:00"
            },
            "id": "7473784b-46a8-470c-b9a6-fe38a01025aa",
            "issued": "2021-12-10T13:30:10+01:00",
            "meta": {
              "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
              "source": "http://example.com/HappyHospital",
              "versionId": "VERSION_ID"
            },
            "resourceType": "Observation",
            "status": "final",
            "subject": {
              "reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"
            },
            "valueQuantity": {
              "code": "g/dL",
              "system": "http://unitsofmeasure.org",
              "unit": "g/dl",
              "value": 7.2
            }
          },
          "search": {
            "mode": "match"
          }
        }
      ],
      "link": [
        {
          "relation": "search",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?status=final"
        },
        {
          "relation": "first",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?status=final"
        },
        {
          "relation": "self",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?status=final"
        }
      ],
      "resourceType": "Bundle",
      "total": 1,
      "type": "searchset"
    }
    
  3. El profesional sanitario Jeffrey Brown (identificado por Practitioner/12942879-f89f-41ae-aa80-0b911b649833) usa la aplicación App/123 para buscar todas las Observations del paciente Darcy.
  4. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 env/App/123" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation?subject:Patient.name=Darcy"

    Deberías recibir una respuesta JSON similar a la siguiente:

    {
      "link": [
        {
          "relation": "search",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject%3APatient.name=Darcy"
        },
        {
          "relation": "first",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject%3APatient.name=Darcy"
        },
        {
          "relation": "self",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject%3APatient.name=Darcy"
        }
      ],
      "resourceType": "Bundle",
      "total": 0,
      "type": "searchset"
    }
    

    La consulta anterior es una búsqueda encadenada. Como se ha denegado el acceso al recurso Patient Darcy (identificado por Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2) en el escenario de consentimiento actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 env/App/123, el servidor FHIR no devuelve ninguna Observation del paciente, como si no existiera.

  5. El profesional sanitario Jeffrey Brown (identificado con Practitioner/12942879-f89f-41ae-aa80-0b911b649833) usa la aplicación App/123 para buscar todas las observaciones de la paciente Darcy con fines de tratamiento de emergencia.
  6. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 purp/v3/ETREAT env/App/123" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation?subject:Patient.name=Darcy"

    Deberías recibir una respuesta JSON similar a la siguiente:

    {
      "entry": [
        {
          "fullUrl": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/68583624-9921-4158-8754-2a306c689abd",
          "resource": {
            "code": {
              "coding": [
                {
                  "code": "15074-8",
                  "display": "Glucose [Moles/volume] in Blood",
                  "system": "http://loinc.org"
                }
              ]
            },
            "effectivePeriod": {
              "start": "2021-12-01T05:30:10+01:00"
            },
            "id": "68583624-9921-4158-8754-2a306c689abd",
            "issued": "2021-12-01T13:30:10+01:00",
            "meta": {
              "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
              "versionId": "VERSION_ID"
            },
            "resourceType": "Observation",
            "status": "final",
            "subject": {
              "reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"
            },
            "valueQuantity": {
              "code": "mmol/L",
              "system": "http://unitsofmeasure.org",
              "unit": "mmol/l",
              "value": 6.3
            }
          },
          "search": {
            "mode": "match"
          }
        },
        {
          "fullUrl": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa",
          "resource": {
            "code": {
              "coding": [
                {
                  "code": "718-7",
                  "display": "Hemoglobin [Mass/volume] in Blood",
                  "system": "http://loinc.org"
                }
              ]
            },
            "effectivePeriod": {
              "start": "2021-12-10T05:30:10+01:00"
            },
            "id": "7473784b-46a8-470c-b9a6-fe38a01025aa",
            "issued": "2021-12-10T13:30:10+01:00",
            "meta": {
              "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
              "source": "http://example.com/HappyHospital",
              "versionId": "VERSION_ID"
            },
            "resourceType": "Observation",
            "status": "final",
            "subject": {
              "reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"
            },
            "valueQuantity": {
              "code": "g/dL",
              "system": "http://unitsofmeasure.org",
              "unit": "g/dl",
              "value": 7.2
            }
          },
          "search": {
            "mode": "match"
          }
        }
      ],
      "link": [
        {
          "relation": "search",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject:Patient.name=Darcy"
        },
        {
          "relation": "first",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject:Patient.name=Darcy"
        },
        {
          "relation": "self",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/?subject:Patient.name=Darcy"
        }
      ],
      "resourceType": "Bundle",
      "total": 2,
      "type": "searchset"
    }
    
  7. El profesional sanitario Jeffrey Brown (identificado con Practitioner/12942879-f89f-41ae-aa80-0b911b649833) busca observaciones con status=final con dos fines: tratamiento e investigación.
  8. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 purp/v3/TREAT purp/v3/HRESCH" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation?status=final"

    Deberías recibir una respuesta JSON similar a la siguiente:

    {
      "issue": [
        {
          "code": "security",
          "details": {
            "text": "permission_denied"
          },
          "diagnostics": "the maximum number of allowed consent purpose scopes is 1, got 2",
          "severity": "error"
        }
      ],
      "resourceType": "OperationOutcome"
    }
    

    En este caso, el profesional sanitario Jeffrey Brown debería eliminar un propósito innecesario de `X-Consent-Scope` en la solicitud.

  9. Un administrador de TI de un hospital usa bypass para buscar a todos los profesionales del hospital.
  10. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: bypass actor/Admin/ef0592c9-6724-467e-878d-f879e537cd15 env/net/HappyNet" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner?"

    Como se ha proporcionado bypass, se han omitido las comprobaciones de consentimiento. Deberías recibir una respuesta JSON similar a la siguiente:

    {
      "entry": [
        {
          "fullUrl": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner/12942879-f89f-41ae-aa80-0b911b649833",
          "resource": {
            "active": true,
            "birthDate": "1970-05-23",
            "gender": "male",
            "id": "12942879-f89f-41ae-aa80-0b911b649833",
            "meta": {
              "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
              "versionId": "VERSION_ID"
            },
            "name": [
              {
                "family": "Brown",
                "given": [
                  "Jeffrey"
                ],
                "use": "official"
              }
            ],
            "resourceType": "Practitioner"
          },
          "search": {
            "mode": "match"
          }
        }
      ],
      "link": [
        {
          "relation": "search",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner/?"
        },
        {
          "relation": "first",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner/?"
        },
        {
          "relation": "self",
          "url": "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Practitioner/?"
        }
      ],
      "resourceType": "Bundle",
      "total": 1,
      "type": "searchset"
    }
    

La API Cloud Healthcare admite la obtención de recursos FHIR en un almacén FHIR determinado con actor, purpose y environment como parámetros de consulta. La respuesta solo contiene los recursos para los que se ha obtenido el consentimiento.

  1. El profesional sanitario Jeffrey Brown (identificado con Practitioner/12942879-f89f-41ae-aa80-0b911b649833) usa la aplicación App/123 para leer la medición de hemoglobina del paciente (en este ejemplo, Observation/7473784b-46a8-470c-b9a6-fe38a01025aa).
  2. curl -X GET \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 env/App/123" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa"

    Como se ha dado el consentimiento al solicitante, la respuesta es el contenido del recurso Observation.

    {
      "code": {
        "coding": [
          {
            "code": "718-7",
            "display": "Hemoglobin [Mass/volume] in Blood",
            "system": "http://loinc.org"
          }
        ]
      },
      "effectivePeriod": {
        "start": "2021-12-10T05:30:10+01:00"
      },
      "id": "7473784b-46a8-470c-b9a6-fe38a01025aa",
      "issued": "2021-12-10T13:30:10+01:00",
      "meta": {
        "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
        "source": "http://example.com/HappyHospital",
        "versionId": "VERSION_ID"
      },
      "resourceType": "Observation",
      "status": "final",
      "subject": {
        "reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"
      },
      "valueQuantity": {
        "code": "g/dL",
        "system": "http://unitsofmeasure.org",
        "unit": "g/dl",
        "value": 7.2
      }
    }
    
  3. El profesional sanitario Jeffrey Brown (identificado por Practitioner/12942879-f89f-41ae-aa80-0b911b649833) usa una aplicación desconocida App/unknown para leer la medición de hemoglobina del paciente (en este ejemplo, Observation/7473784b-46a8-470c-b9a6-fe38a01025aa).
  4. curl -X GET \
      -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
      -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 env/App/unknown" \
      "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa"

    Se ha denegado la solicitud porque el acceso al límite del solicitante (`App/unknown`) no está permitido por el consentimiento del paciente.

    {
      "issue": [
        {
          "code": "security",
          "details": {
            "text": "permission_denied"
          },
          "diagnostics": "Consent access denied or the resource being accessed does not exist",
          "severity": "error"
        }
      ],
      "resourceType": "OperationOutcome"
    }
    
  5. El profesional sanitario Jeffrey Brown (identificado con Practitioner/12942879-f89f-41ae-aa80-0b911b649833) realiza una investigación biomédica con la aplicación App/golden y lee la fecha de nacimiento de Darcy (en este ejemplo, Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2).
  6. curl -X GET \
      -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
      -H "X-Consent-Scope: actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833 purp/v3/BIORCH env/App/golden" \
      "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"

    Como se ha dado el consentimiento a la persona que ha enviado la solicitud, la respuesta es el contenido del recurso Patient.

    {
      "active": true,
      "birthDate": "1990-01-01",
      "gender": "female",
      "id": "3c6aa096-c054-4c22-b2b4-1e4a4d203de2",
      "meta": {
        "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
        "versionId": "VERSION_ID",
        "tag": [{
          "system": "http://terminology.hl7.org/CodeSystem/common-tags",
          "code": "employee"
        }]
      },
      "name": [
        {
          "family": "Smith",
          "given": [
            "Darcy"
          ],
          "use": "official"
        }
      ],
      "resourceType": "Patient"
    }
    
  7. El profesional sanitario Jeffrey Brown (identificado por Practitioner/12942879-f89f-41ae-aa80-0b911b649833) solicita acceso de emergencia no autorizado al historial de un paciente mediante el protocolo "break-the-glass". En este ejemplo, Observation/7473784b-46a8-470c-b9a6-fe38a01025aa.
  8. curl -X GET \
      -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
      -H "X-Consent-Scope: btg actor/Practitioner/12942879-f89f-41ae-aa80-0b911b649833" \
      "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Observation/7473784b-46a8-470c-b9a6-fe38a01025aa"

    Como el método de autorización del consentimiento es btg, el servidor omite las comprobaciones del consentimiento. La respuesta es el contenido del recurso Observation.

    {
      "code": {
        "coding": [
          {
            "code": "718-7",
            "display": "Hemoglobin [Mass/volume] in Blood",
            "system": "http://loinc.org"
          }
        ]
      },
      "effectivePeriod": {
        "start": "2021-12-10T05:30:10+01:00"
      },
      "id": "7473784b-46a8-470c-b9a6-fe38a01025aa",
      "issued": "2021-12-10T13:30:10+01:00",
      "meta": {
        "lastUpdated": "2022-09-01T17:31:40.423469+00:00",
        "source": "http://example.com/HappyHospital",
        "versionId": "VERSION_ID"
      },
      "resourceType": "Observation",
      "status": "final",
      "subject": {
        "reference": "Patient/3c6aa096-c054-4c22-b2b4-1e4a4d203de2"
      },
      "valueQuantity": {
        "code": "g/dL",
        "system": "http://unitsofmeasure.org",
        "unit": "g/dl",
        "value": 7.2
      }
    }
    

En las siguientes secciones se describen los métodos de aplicación del consentimiento admitidos en la API Cloud Healthcare y cómo se aplica el acceso a los recursos cuando se hace una solicitud que tiene en cuenta el consentimiento.

Cuando se envía una solicitud, el servidor de autorización es el encargado de generar tokens de acceso con el ámbito de consentimiento pertinente.

Definir encabezado HTTP

Los ámbitos de consentimiento se transfieren a la API Cloud Healthcare mediante la cabecera HTTP X-Consent-Scope. La API Cloud Healthcare usa este encabezado para aplicar el control de acceso basado en el consentimiento a los datos de los almacenes FHIR.

Una solicitud de FHIR puede admitir un número limitado de ámbitos de entrada de consentimiento. En una solicitud FHIR determinada se pueden incluir hasta tres entradas de actor, una de purp y una de env.

En el caso de los ámbitos especiales, una solicitud de FHIR puede admitir uno de los siguientes valores: btg o bypass.

Definir encabezados HTTP para aplicaciones de confianza

Esta sección solo es obligatoria si usas un servidor de autorización controlado por el cliente. En este caso, también debes usar un SMARTproxy o un proxy similar.

Algunas aplicaciones de confianza pueden hacer llamadas directamente a la API Cloud Healthcare con los ámbitos de consentimiento en el encabezado HTTP especificado. Esto permite aplicar el consentimiento directamente sin necesidad de un SMARTproxy u otro proxy para convertir entre servidores de autorización externos y Google Cloud.

Por ejemplo, tu aplicación puede registrarse para un subconjunto de ámbitos, como un ámbito de aplicación environment, o bien puede presentar un widget de selección para definir algunas entradas de ámbito, como el purpose del accesor.

Un usuario o una aplicación de confianza también podrían usar las entradas de ámbito btg o bypass, que están sujetas a revisiones posteriores a la auditoría.

La API Cloud Healthcare ofrece compatibilidad integrada con la aplicación de Consentimiento de FHIR en función de los ámbitos de consentimiento de entrada. Los administradores de almacenes FHIR son responsables de crear y configurar un servidor de autorización fuera de la API Cloud Healthcare que conceda ámbitos de consentimiento.

Token de acceso de ejemplo

En el siguiente ejemplo se muestra un token de acceso codificado en base64:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJpc3MiOiJjb25zZW50LnRva2VuLm9yZyIsImlhdCI6MTYxMjg4NDA4NSwiZXhwIjoxNjQ0NDIwMDg1LCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJkb2N0b3IuZ2FicmllbGFAZXhhbXBsZS5jb20iLCJzY29wZSI6Im9pZGMgYWN0b3IvUHJhY3RpdGlvbmVyLzEyMyBhY3Rvci9Hcm91cC85OTkgcHVycC92My9UUkVBVCBlbnYvQXBwL2FiYyJ9.fC7ljkVUUx8fwUOrJuONcrqA-WKC-k_Bclzlgds0Cq6H_gEe3nUjPlSOCTQsIdYB

Después de decodificar el token de acceso, verás que contiene la siguiente carga útil:

{
  "iss": "consent.token.org",
  "iat": 1612884085,
  "exp": 1644420085,
  "aud": "www.example.com",
  "sub": "doctor.gabriela@example.com",
  "scope": "oidc actor/Practitioner/123 actor/Group/999 purp/v3/TREAT env/App/abc"
}

Configurar SMARTProxy

SMARTProxy es un proxy de código abierto de Google que ofrece las siguientes funciones:

  • Permite que el servidor FHIR de la API Cloud Healthcare acepte y valide tokens de acceso con consentimiento.

  • Permite que la implementación de FHIR en la API Cloud Healthcare incluya tokens de acceso con consentimiento como parte de la gestión y el modelo de permisos de la API Cloud Healthcare.

  • También admite funciones de token para la compatibilidad con SMART on FHIR.

Cuando haces una solicitud para recuperar datos de la API Cloud Healthcare a través de SMARTProxy, ocurre lo siguiente:

  1. SMARTProxy acepta una solicitud de un cliente que contiene un token que tiene en cuenta el consentimiento.

  2. SMARTProxy valida el token con consentimiento a través de un servidor de autorización JWT que es de tu propiedad.

  3. SMARTProxy lee los ámbitos del token que tiene en cuenta el consentimiento y los transfiere a la API Cloud Healthcare a través del encabezado HTTP.

  4. La API Cloud Healthcare recibe los encabezados y los valida para aplicar las directivas de consentimiento en la solicitud. A continuación, la API de Cloud Healthcare devuelve una respuesta al cliente a través de SMARTProxy.

Configurar una cuenta de servicio de Google Cloud

Un proxy solo puede tener una cuenta de servicio. Google Cloud Si varios clientes usan el mismo proxy, utilizarán la misma cuenta de servicio. Ten cuidado al compartir una cuenta de servicio con varios clientes por los siguientes motivos:

Por ejemplo, si llamas directamente a la API Cloud Healthcare con tu cuenta de Google para autenticarte, Cloud Audit Logs registrará tu dirección de correo como dirección de correo principal. Cuando usas un proxy para llamar a la API Cloud Healthcare, el proxy usa su propia cuenta de servicio y la dirección de correo principal es la dirección de correo de la cuenta de servicio. La cuenta original no se define.

Registros de auditoría

Los registros de auditoría se generan cuando hay una solicitud de acceso o cuando cambia la aplicación del acceso a los recursos.

de auditoría de acceso a datos.

Si los registros de auditoría están habilitados en el almacén FHIR, se incluye un campo de metadatos consentMode en los registros de auditoría disponibles en Cloud Logging. El elemento consentMode puede tener uno de los siguientes valores:

  • off: la configuración del almacén FHIR tiene el valor consentConfig.accessEnforced definido como false y no permite solicitudes que tengan en cuenta el consentimiento.

  • emptyScope: el almacén FHIR tiene el valor consentConfig.accessEnforced definido como true, pero no se ha incluido un encabezado de ámbito de consentimiento. Por lo tanto, no se han aplicado los consentimientos.

  • enforced: el almacén FHIR tiene el valor consentConfig.accessEnforced definido como true y el encabezado del ámbito de consentimiento estaba presente. Por lo tanto, los consentimientos se evaluaron y se aplicaron en la solicitud.

  • btg: la solicitud FHIR tenía btg en el encabezado del ámbito de consentimiento. Por lo tanto, se han omitido las comprobaciones de consentimiento. Esta solicitud se debe usar en caso de emergencia y solo está sujeta a una revisión posterior.

  • bypass: la solicitud FHIR solo tenía bypass en el encabezado del ámbito de consentimiento. Por este motivo, se han omitido las comprobaciones de consentimiento. Esta solicitud está pensada para que la use un flujo de trabajo de confianza (como un administrador o una aplicación de confianza en lugar de usuarios finales) para que este registro de auditoría sea diferente del btg, que se usa para las comprobaciones de gobernanza de datos.

También puede definir access_determination_log_config como VERBOSE para registrar más información sobre por qué se concede o se deniega una solicitud.

Registros de auditoría de cambios en la aplicación del acceso

Cuando cambia el recurso base del compartimento (por ejemplo, si se elimina la etiqueta employee de un paciente): el control de acceso al recurso modificado y a su compartimento puede cambiar debido a la política de cascada de administrador. Se volverán a indexar todos los recursos del compartimento. El progreso de la reindexación de cada actualización de recursos base de compartimento se puede monitorizar en Cloud Logging con el filtro jsonPayload.@type="type.googleapis.com/google.cloud.healthcare.logging.FhirConsentCascadeLogEntry".

Registro de progreso de reindexación en cascada de ejemplo

{
  "insertId": "tz2gtza8",
  "jsonPayload": {
    "@type": "type.googleapis.com/google.cloud.healthcare.logging.FhirConsentCascadeLogEntry",
    "state": "STATE_FINISHED",
    "affectedResources": "2",
    "lastUpdated": "YYYY-MM-DDTHH:MM:SS+ZZ:ZZ",
    "compartmentBaseResourceName": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Patient/PATIENT_RESOURCE_ID/_history/PATIENT_RESOURCE_VERSION"
  },
  "resource": {
    "type": "healthcare_fhir_store",
    "labels": {
      "location": "LOCATION",
      "dataset_id": "DATASET_ID",
      "fhir_store_id": "FHIR_STORE_ID",
      "project_id": "PROJECT_ID"
    }
  },
  "timestamp": "YYYY-MM-DDTHH:MM:SS+ZZ:ZZ",
  "severity": "INFO",
  "logName": "projects/PROJECT_ID/logs/healthcare.googleapis.com%2Fconsent_cascading_fhir",
  "receiveTimestamp": "YYYY-MM-DDTHH:MM:SS+ZZ:ZZ"
}

jsonPayload.state es el estado de la operación de reindexación, jsonPayload.affectedResources es el número de recursos de compartimento reindexados y jsonPayload.lastUpdated es la marca de tiempo de la actualización del recurso de paciente. Si la operación acaba de iniciarse, no aparecerán jsonPayload.state="STATE_STARTED" ni jsonPayload.affectedResources.

Restricciones y limitaciones

En esta sección se muestran las restricciones y los límites de FHIR R4, pero las mismas restricciones y límites se aplican a FHIR STU3.

Tipo Restricciones y límites
Recurso Consent
  • Solo se admite un Consent.provision. No se admiten varias provisiones ni provisiones anidadas.
  • Al menos 1 Consent.provision.actor y un máximo de 25:
    • Consent.provision.actor.role debe ser http://terminology.hl7.org/CodeSystem/v3-RoleCode.
    • Consent.provision.actor.code debe ser GRANTEE o HPOWATT.
  • Como máximo, 1 Consent.provision.purpose:
    • Consent.provision.purpose.system debe ser http://terminology.hl7.org/CodeSystem/v3-ActReason.
    • Consent.provision.purpose.code no está vacío y tiene como máximo 13 caracteres.
  • Como máximo 1 environment:
    • Consent.provision.extension.url debe ser https://g.co/fhir/medicalrecords/Environment.
    • La longitud combinada del sistema y el código debe ser inferior a 15 caracteres.
  • Si se filtra por tipo de recurso, Consent.provision.class.system debe ser http://hl7.org/fhir/resource-types.
  • Si se filtra por fuente de datos, Consent.provision.extension.url debe ser https://g.co/fhir/medicalrecords/DataSource.
  • Si se filtra por etiqueta de datos, Consent.provision.extension.url debe ser https://g.co/fhir/medicalrecords/DataTag.
    • La etiqueta de datos puede ser una extensión compleja, anidada hasta un nivel, para describir una política que coincida con los recursos que tengan todas las etiquetas especificadas (interpretadas conjuntamente).
    • Se admiten 5 etiquetas anidadas como máximo.
  • Como máximo, 100 valores para todos los atributos repetidos, a menos que se indique lo contrario en esta fila.
Modelo de cumplimiento
  • Cada paciente puede tener hasta 200 recursos active Consent a la vez.
  • Cada tienda puede tener hasta 200 políticas de administrador active aplicadas a la vez.
  • El formato compacto especial del conjunto de todas las directivas de consentimiento de todos los consentimientos activos de un paciente determinado no debe superar un umbral de tamaño establecido. Normalmente, hay capacidad suficiente para codificar miles de directivas de consentimiento, a menos que haya una gran cantidad de cadenas de recursos muy largas. Por ejemplo:
    • Cientos de consentimientos en fuentes de datos y etiquetas de datos únicos, cada uno de los cuales es muy largo, consumen mucho espacio.
    • Un solo paciente con 3000 entradas de identificador de recurso Consent.provision.data.reference únicas en muchos consentimientos activos, cada uno de los cuales especifica un Consent.provision.actor único, usa el espacio de forma más agresiva que las provisiones que no especifican ninguna restricción de referencia de datos o que contienen muchas de las mismas cadenas de referencia de actor.
  • Cada recurso puede tener hasta 1000 directivas de consentimiento de todos los consentimientos que se le apliquen.
X-Consent-Scope
  • Debe haber entre una y tres entradas actor.
  • Máximo una entrada de purp:
    • Cada entrada de purp debe tener el formato system/code (v3 es el sistema registrado de http://terminology.hl7.org/CodeSystem/v3-ActReason).
    • La longitud del código debe ser inferior a 13.
  • Máximo una entrada de env:
    • Cada entrada de env debe tener el formato system/code.
    • La longitud combinada del sistema y el código debe ser inferior a 15.
  • btg requiere al menos una entrada de actor.
  • bypass requiere al menos una entrada actor y una entrada env.
Métodos admitidos
Rendimiento
  • ApplyConsents y ApplyAdminConsents se escalan de forma similar o mejor que ImportResources.
  • En cuanto a las solicitudes que tienen en cuenta el consentimiento:
    • Nuestro modelo de consentimiento se ha optimizado para mejorar el rendimiento de las operaciones CRUD, incluida la búsqueda a gran escala en muchos recursos y pacientes.
    • La lectura de recursos individuales puede tener un impacto marginal en la latencia de las solicitudes. Sin embargo, el rendimiento de la búsqueda varía en función de la consulta base y del número de ámbitos de consentimiento, lo que lleva a que se activen más criterios de acceso durante una búsqueda.
    • Te recomendamos que realices tus propias pruebas de rendimiento con varios parámetros de solicitud FHIR representativos para determinar las características de rendimiento de tus casos prácticos en función de las características de tus datos, como el número de recursos de un tipo de recurso de búsqueda determinado que haya en el almacén FHIR.
    • Nuestra solución mantiene la ingesta y las actualizaciones de todos los recursos, incluidos los de consentimiento, de forma ligera, de modo que el rendimiento durante la ingesta y otras formas de tráfico de escritura puedan continuar con un impacto mínimo.

Prácticas recomendadas

En las siguientes secciones se describen las prácticas recomendadas al usar el control de acceso de FHIR.

Prácticas recomendadas generales

  • No importes recursos FHIR y llames a ApplyConsents o ApplyAdminConsents en paralelo. Te recomendamos que primero importes recursos FHIR y, después, llames a ApplyConsents o ApplyAdminConsents. Sin embargo, si los recursos que se van a importar no incluyen ningún recurso Patient o Consent, el modelo de cumplimiento no se verá afectado y no será necesario procesar consentimientos ni políticas de administrador.

  • No crees búsquedas personalizadas y llames a ApplyConsents en paralelo. Te recomendamos que los hagas uno después del otro.

  • Si tus flujos de trabajo requieren llamar a varios ApplyConsents en PatientScope disjuntos, se pueden llamar en paralelo.

  • ApplyAdminConsents puede ejecutarse en paralelo con cualquier número de ApplyConsents, pero no con otro ApplyAdminConsents.

  • Al configurar el proxy, restringe la cuenta de servicio de IAM con permisos de solo lectura para evitar que se escriban los datos de un paciente en los registros de otro.

  • No utilice el proxy de consentimiento al crear o actualizar registros.

  • Valida todas las solicitudes de escritura para evitar modificaciones inesperadas de datos de pacientes.

  • Cuando se aplican consentimientos en cascada, los recursos base de los compartimentos deben importarse primero, seguidos del resto de los recursos del compartimento. También puedes envolver todos los recursos de compartimento en un solo paquete e ingerirlos mediante fhir.executeBundle.

Eliminar recurso Patient

Cuando elimine un recurso Patient, si también quiere eliminar la aplicación del consentimiento de ese paciente (sobre todo cuando FhirStore.disableReferentialIntegrity sea true), le recomendamos que siga este orden de operaciones:

  1. Elimina todos los recursos Consent que pertenezcan al recurso Patient.

  2. Llama a ApplyConsents con el filtro PatientScope.

Para configurar una tienda que ya tengas para que pueda acceder a los consentimientos, sigue estos pasos:

  1. Usa UpdateFhirStore para definir el ConsentConfig con la opción de cumplimiento del consentimiento version como V1 y asigna el valor true a accessEnforced.

    curl -X PATCH \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json" \
        --data "{
          'consentConfig': {
            'version': 'V1',
            'accessEnforced': true
          }
        }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID?update_mask=consentConfig"
  2. Procesar consentimientos de pacientes o políticas de administración

    1. ApplyConsents para los consentimientos de los pacientes
    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json" \
        --data "{'validateOnly': false}" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:applyConsents"
    1. ApplyAdminConsents para las políticas de administrador y las políticas de administrador en cascada.
    curl -X POST \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json" \
        --data "{
          'newConsentsList': {
              'names': [
              'projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/RESOURCE_ID_1/_history/VERSION_ID_1',
              ...
              'projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID/fhir/Consent/RESOURCE_ID_N/_history/VERSION_ID_N'
              ]
          },
          'validateOnly': false
        }" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:applyAdminConsents"

Con qué frecuencia se deben ejecutar ApplyConsents o ApplyAdminConsents

  • Cuando el campo ConsentConfig no está definido: el campo ConsentConfig no está definido tanto cuando se crea un almacén FHIR por primera vez como cuando se borra el campo ConsentConfig. Una vez que se haya anulado el campo ConsentConfig, debes repetir el proceso para configurar la tienda para el acceso al consentimiento antes de enviar solicitudes que tengan en cuenta el consentimiento para evitar que se evalúen políticas de cumplimiento obsoletas.

  • Cuando cambia el modelo de cumplimiento: cuando se crea, actualiza o elimina un recurso Consent, cambia el modelo de cumplimiento. En esos casos, debes llamar al ApplyConsents o al ApplyAdminConsents para que se apliquen los cambios.

    • Si puedes hacer un seguimiento de los cambios de los pacientes con consentimiento, te recomendamos que uses el filtro PatientScope para evitar tener que volver a procesar toda la tienda. Este filtro es útil para actualizar inmediatamente la aplicación de un pequeño conjunto de pacientes.

    • También puedes ejecutar ApplyConsents periódicamente con el TimeRange filtro. Este filtro es útil cuando no es fundamental que los datos se actualicen de inmediato. Por ejemplo, la siguiente solicitud actualiza la aplicación de las medidas por los cambios en el consentimiento entre las 00:00 (UTC) del 20/09/2022 y las 00:00 (UTC) del 21/09/2022.

      curl -X POST \
        -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
        -H "Content-Type: application/json" \
        --data "{
           'validateOnly': false,
           'timeRange': {
             'start': '2022-09-20T00:00:00Z',
             'end': '2022-09-21T00:00:00Z',
           }
          }" \
        "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:applyConsents"

El visor de consentimiento de FHIR muestra las políticas de control de acceso. Proporciona una tabla que contiene ámbitos de consentimiento para representar las reglas de control de acceso de FHIR.

Antes de usar el visor de consentimiento de FHIR, asegúrate de que se cumplen los siguientes requisitos:

Para ver el visor de consentimiento de FHIR, sigue estos pasos:

Siguientes pasos