diff --git a/.kokoro/healthcare-datasets.cfg b/.kokoro/healthcare-datasets.cfg new file mode 100644 index 0000000000..01bd562ffa --- /dev/null +++ b/.kokoro/healthcare-datasets.cfg @@ -0,0 +1,22 @@ +# Format: //devtools/kokoro/config/proto/build.proto + +# Set the folder in which the tests are run +env_vars: { + key: "PROJECT" + value: "healthcare/datasets" +} + +# Tell the trampoline which build file to use. +env_vars: { + key: "TRAMPOLINE_BUILD_FILE" + value: "github/nodejs-docs-samples/.kokoro/build.sh" +} + +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 71386 + keyname: "healthcare-api-nodejs-samples-kokoro-api-key" + } + } +} diff --git a/healthcare/datasets/README.md b/healthcare/datasets/README.md new file mode 100644 index 0000000000..f3f26c010c --- /dev/null +++ b/healthcare/datasets/README.md @@ -0,0 +1,37 @@ +Google Cloud Platform logo + +# Cloud Healthcare API Node.js Dataset Management example + +This sample app demonstrates dataset management for the Cloud Healthcare API. + +# Setup + +Run the following command to install the library dependencies for Node.js: + + npm install + +# Running the sample + + Commands: + datasets.js createDataset Creates a new health dataset. + datasets.js deleteDataset Deletes the specified health dataset and all data + contained in the dataset. + datasets.js getDataset Gets any metadata associated with a dataset. + datasets.js listDatasets Lists the datasets in the given GCP project. + datasets.js patchDataset Updates dataset metadata. + datasets.js deidentifyDataset Creates a new dataset containing de-identified data from + the source dataset. + + Options: + --version Show version number [boolean] + --apiKey, -a The API key used for discovering the API. Defaults to + the value of API_KEY environment variable. + [string] + --cloudRegion, -c [string] [default: "us-central1"] + --projectId, -p The Project ID to use. Defaults to the value of the GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT + environment variables. [string] + --serviceAccount, -s The path to your service credentials JSON. + [string] + --help Show help [boolean] + +For more information, see https://cloud.google.com/healthcare/docs diff --git a/healthcare/datasets/datasets.js b/healthcare/datasets/datasets.js new file mode 100644 index 0000000000..8993f8fa05 --- /dev/null +++ b/healthcare/datasets/datasets.js @@ -0,0 +1,296 @@ +/** + * Copyright 2018, Google, LLC + * Licensed under the Apache License, Version 2.0 (the `License`); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an `AS IS` BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const {google} = require('googleapis'); + +// [START healthcare_create_dataset] +function createDataset (client, projectId, cloudRegion, datasetId) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + // const datasetId = 'my-dataset'; + const parentName = `projects/${projectId}/locations/${cloudRegion}`; + + const request = {parent: parentName, datasetId: datasetId}; + + client.projects.locations.datasets.create(request) + .then(() => { + console.log(`Created dataset: ${datasetId}`); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_create_dataset] + +// [START healthcare_delete_dataset] +function deleteDataset (client, projectId, cloudRegion, datasetId, cb) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + // const datasetId = 'my-dataset'; + const datasetName = + `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}`; + + const request = {name: datasetName}; + + client.projects.locations.datasets.delete(request) + .then(() => { + console.log(`Deleted dataset: ${datasetId}`); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_delete_dataset] + +// [START healthcare_get_dataset] +function getDataset (client, projectId, cloudRegion, datasetId) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + // const datasetId = 'my-dataset'; + const datasetName = + `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}`; + + const request = {name: datasetName}; + + client.projects.locations.datasets.get(request) + .then(results => { + console.log('Got dataset:\n', results.data); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_get_dataset] + +// [START healthcare_list_datasets] +function listDatasets (client, projectId, cloudRegion) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + const parentName = `projects/${projectId}/locations/${cloudRegion}`; + + const request = {parent: parentName}; + + client.projects.locations.datasets.list(request) + .then(results => { + console.log('Datasets:', results.data); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_list_datasets] + +// [START healthcare_patch_dataset] +function patchDataset (client, projectId, cloudRegion, datasetId, timeZone) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + // const datasetId = 'my-dataset'; + // const timeZone = 'GMT' + const datasetName = + `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}`; + + const request = { + name: datasetName, + updateMask: 'timeZone', + resource: {timeZone: timeZone} + }; + + client.projects.locations.datasets.patch(request) + .then(results => { + console.log( + `Dataset ${datasetId} patched with time zone ${ + results.data.timeZone}`); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_patch_dataset] + +// [START healthcare_deidentify_dataset] +function deidentifyDataset ( + client, projectId, cloudRegion, sourceDatasetId, destinationDatasetId, + whitelistTags) { + // Client retrieved in callback + // getClient(serviceAccountJson, function(client) {...}); + // const cloudRegion = 'us-central1'; + // const projectId = 'adjective-noun-123'; + // const sourceDatasetId = 'my-dataset'; + // const destinationDatasetId = 'my-destination-dataset'; + // const whitelistTags = 'PatientID'; + const sourceDatasetName = `projects/${projectId}/locations/${ + cloudRegion}/datasets/${sourceDatasetId}`; + const destinationDatasetName = `projects/${projectId}/locations/${ + cloudRegion}/datasets/${destinationDatasetId}`; + + const request = { + sourceDataset: sourceDatasetName, + destinationDataset: destinationDatasetName, + resource: {config: {dicom: {whitelistTags: whitelistTags}}} + }; + + client.projects.locations.datasets.deidentify(request) + .then(results => { + console.log(`De-identified data written from dataset + ${sourceDatasetId} to dataset ${destinationDatasetId}`); + }) + .catch(err => { + console.error(err); + }); +} +// [END healthcare_deidentify_dataset] + +// [START healthcare_get_client] +// Returns an authorized API client by discovering the Healthcare API with +// the provided API key. +function getClient (apiKey, serviceAccountJson, cb) { + const API_VERSION = 'v1alpha'; + const DISCOVERY_API = 'https://healthcare.googleapis.com/$discovery/rest'; + + google.auth + .getClient({scopes: ['https://www.googleapis.com/auth/cloud-platform']}) + .then(authClient => { + const discoveryUrl = `${DISCOVERY_API}?labels=CHC_ALPHA&version=${ + API_VERSION}&key=${apiKey}`; + + google.options({auth: authClient}); + + google.discoverAPI(discoveryUrl) + .then((client) => { + cb(client); + }) + .catch((err) => { + console.log(`Error during API discovery: ${err}`); + }); + }); +} +// [END healthcare_get_client] + +require(`yargs`) // eslint-disable-line + .demand(1) + .options({ + apiKey: { + alias: 'a', + default: process.env.API_KEY, + description: 'The API key used for discovering the API. ' + + 'Defaults to the value of the API_KEY environment variable.', + requiresArg: true, + type: 'string' + }, + cloudRegion: { + alias: 'c', + default: 'us-central1', + requiresArg: true, + type: 'string' + }, + projectId: { + alias: 'p', + default: process.env.GCLOUD_PROJECT || process.env.GOOGLE_CLOUD_PROJECT, + description: + 'The Project ID to use. Defaults to the value of the ' + + 'GCLOUD_PROJECT or GOOGLE_CLOUD_PROJECT environment variables.', + requiresArg: true, + type: 'string' + }, + serviceAccount: { + alias: 's', + default: process.env.GOOGLE_APPLICATION_CREDENTIALS, + description: 'The path to your service credentials JSON.', + requiresArg: true, + type: 'string' + } + }) + .command( + `createDataset `, `Creates a new health dataset.`, {}, + (opts) => { + const cb = function (client) { + createDataset( + client, opts.projectId, opts.cloudRegion, opts.datasetId); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .command( + `deleteDataset `, + `Deletes the specified health dataset and all data contained + in the dataset.`, + {}, + (opts) => { + const cb = function (client) { + deleteDataset( + client, opts.projectId, opts.cloudRegion, opts.datasetId); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .command( + `getDataset `, + `Gets any metadata associated with a dataset.`, {}, + (opts) => { + const cb = function (client) { + getDataset( + client, opts.projectId, opts.cloudRegion, opts.datasetId); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .command( + `listDatasets`, `Lists the datasets in the given GCP project.`, {}, + (opts) => { + const cb = function (client) { + listDatasets(client, opts.projectId, opts.cloudRegion); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .command( + `patchDataset `, `Updates dataset metadata.`, {}, + (opts) => { + const cb = function (client) { + patchDataset( + client, opts.projectId, opts.cloudRegion, opts.datasetId, + opts.timeZone); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .command( + `deidentifyDataset + `, + `Creates a new dataset containing de-identified data from the + source dataset.`, + {}, + (opts) => { + const cb = function (client) { + deidentifyDataset( + client, opts.projectId, opts.cloudRegion, opts.sourceDatasetId, + opts.destinationDatasetId, opts.whitelistTags); + }; + getClient(opts.apiKey, opts.serviceAccount, cb); + }) + .wrap(120) + .recommendCommands() + .epilogue( + `For more information, see https://cloud.google.com/healthcare/docs`) + .help() + .strict() + .argv; diff --git a/healthcare/datasets/package.json b/healthcare/datasets/package.json new file mode 100644 index 0000000000..e72d1d8353 --- /dev/null +++ b/healthcare/datasets/package.json @@ -0,0 +1,35 @@ +{ + "name": "nodejs-docs-samples-healthcare", + "version": "0.0.1", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "repository": "GoogleCloudPlatform/nodejs-docs-samples", + "engines": { + "node": ">=6.0.0" + }, + "scripts": { + "test": "ava -T 1m --verbose system-test/*.test.js" + }, + "devDependencies": { + "@google-cloud/nodejs-repo-tools": "^2.3.1", + "ava": "^0.25.0" + }, + "dependencies": { + "googleapis": "^32.0.0", + "uuid": "^3.3.2", + "yargs": "^12.0.1" + }, + "cloud-repo-tools": { + "requiresKeyFile": true, + "requiresProjectId": true, + "test": { + "build": { + "requiredEnvVars": [ + "API_KEY", + "GCLOUD_PROJECT" + ] + } + } + } +} diff --git a/healthcare/datasets/system-test/datasets.test.js b/healthcare/datasets/system-test/datasets.test.js new file mode 100644 index 0000000000..705e08feca --- /dev/null +++ b/healthcare/datasets/system-test/datasets.test.js @@ -0,0 +1,74 @@ +/** + * Copyright 2018, Google, LLC + * Licensed under the Apache License, Version 2.0 (the `License`); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an `AS IS` BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const path = require(`path`); +const test = require(`ava`); +const tools = require(`@google-cloud/nodejs-repo-tools`); +const uuid = require(`uuid`); + +const cmd = `node datasets.js`; +const cwd = path.join(__dirname, `..`); +const datasetId = `dataset-${uuid.v4()}`.replace(/-/gi, '_'); +const destinationDatasetId = `destination-${uuid.v4()}`.replace(/-/gi, '_'); +const whitelistTags = 'PatientID'; + +test.before(tools.checkCredentials); +test.after.always(async () => { + try { + await tools.runAsync( + `${cmd} deleteDataset ${destinationDatasetId}`, cwd); + } catch (err) { } // Ignore error +}); + +test.serial(`should create a dataset`, async t => { + const output = await tools.runAsync( + `${cmd} createDataset ${datasetId}`, cwd); + t.is(output, `Created dataset: ${datasetId}`); +}); + +test.serial(`should get a dataset`, async t => { + const output = await tools.runAsync( + `${cmd} getDataset ${datasetId}`, cwd); + t.regex(output, /name/); + t.regex(output, /timeZone/); +}); + +test.serial(`should patch a dataset`, async t => { + const patchTimeZone = 'GMT'; + const output = await tools.runAsync( + `${cmd} patchDataset ${datasetId} ${patchTimeZone}`, cwd); + t.is(output, `Dataset ${datasetId} patched with time zone ${patchTimeZone}`); +}); + +test.serial(`should list datasets`, async t => { + const output = await tools.runAsync( + `${cmd} listDatasets`, cwd); + t.regex(output, /datasets/); +}); + +test.serial(`should de-identify data in a dataset and write to a new dataset`, async t => { + const output = await tools.runAsync( + `${cmd} deidentifyDataset ${datasetId} ${destinationDatasetId} ${whitelistTags}`, cwd); + t.is(output, `De-identified data written from dataset + ${datasetId} to dataset ${destinationDatasetId}`); +}); + +test.serial(`should delete a dataset`, async t => { + const output = await tools.runAsync( + `${cmd} deleteDataset ${datasetId}`, cwd); + t.is(output, `Deleted dataset: ${datasetId}`); +});