Getting started with Google Cloud Datastore and Node.js
Before running through the steps below, make sure that:
- You have enabled Google Cloud Datastore API.
-
You have your
<dataset-id>
(same identifier as your Google Cloud Project ID ). -
You are
connected
to a Compute Engine instance with both the
datastore
anduserinfo.email
scopes or have a<service-account>
and the<path-to-private-key-file>
. - You have a working Node.js environment.
In order to make API calls to the Datastore, you first need to install google-api-nodejs-client by running the following command:
npm install [email protected]
Then,
download
and unzip the latest version of the
google-cloud-datastore
samples:
unzip google-cloud-datastore-1beta2-rev1-2.1.0.zip
If you are not connected to a Compute Engine instance, make sure to run the following commands (in a bash-like shell):
# convert the .p12 private key file to a .pem file
# if asked to enter import password, use "notasecret"
openssl pkcs12 -in <path-to-private-key-file> -out <path-to-pem-file> -nodes -nocerts
# configure your credentials
export DATASTORE_SERVICE_ACCOUNT=<service-account>
export DATASTORE_PRIVATE_KEY_FILE=<path-to-pem-file>
Finally, run the
adams.js
demo with your
<dataset-id>
as a parameter.
It will prompt for
the question
and validate your answer.
node google-cloud-datastore-1beta2-rev1-2.1.0/nodejs/demos/trivial/adams.js <dataset-id>
Meaning of life? 11
Don't Panic!
The comments in the sample's source explain its behavior in detail:
var util = require('util');
var events = require('events');
var readline = require('readline');
var googleapis = require('googleapis');
var SCOPES = ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/datastore'];
/**
* Adams is a simple command line application using the Datastore API.
*
* It writes an entity to the datastore that represents a Trivia
* question with its answer to your dataset. Does a lookup by key and
* presents the question to the user. If the user gets the right
* answer, it will greet him with a quote from a famous book.
*
* @param {string} datasetId The ID of the dataset.
* @constructor
* @extends {events.EventEmitter}
*/
function Adams(datasetId) {
this.datasetId = datasetId;
this.readline = readline.createInterface({
input: process.stdin,
output: process.stdout
});
this.authorize();
}
util.inherits(Adams, events.EventEmitter);
/**
* Authorize with the Datastore API.
*/
Adams.prototype.authorize = function() {
// First, try to retrieve credentials from Compute Engine metadata server.
this.credentials = new googleapis.auth.Compute();
this.credentials.authorize((function(computeErr) {
if (computeErr) {
var errors = {'compute auth error': computeErr};
// Then, fallback on JWT credentials.
this.credentials = new googleapis.auth.JWT(
process.env['DATASTORE_SERVICE_ACCOUNT'],
process.env['DATASTORE_PRIVATE_KEY_FILE'],
SCOPES);
this.credentials.authorize((function(jwtErr) {
if (jwtErr) {
errors['jwt auth error'] = jwtErr;
this.emit('error', errors);
return;
}
this.connect();
}).bind(this));
}
}).bind(this));
};
/**
* Connect to the Datastore API.
*/
Adams.prototype.connect = function() {
// Build the API bindings for the current version.
googleapis.discover('datastore', 'v1beta2')
.withAuthClient(this.credentials)
.execute((function(err, client) {
if (err) {
this.emit('error', {'connection error': err});
return;
}
// Bind the datastore client to datasetId and get the datasets
// resource.
this.datastore = client.datastore.withDefaultParams({
datasetId: this.datasetId}).datasets;
this.beginTransaction();
}).bind(this));
};
/**
* Start a new transaction.
*/
Adams.prototype.beginTransaction = function() {
this.datastore.beginTransaction({
// Execute the RPC asynchronously, and call back with either an
// error or the RPC result.
}).execute((function(err, result) {
if (err) {
this.emit('error', {'rpc error': err});
return;
}
this.transaction = result.transaction;
this.lookup();
}).bind(this));
};
/**
* Lookup for the Trivia entity.
*/
Adams.prototype.lookup = function() {
// Get entities by key.
this.datastore.lookup({
readOptions: {
// Set the transaction, so we get a consistent snapshot of the
// value at the time the transaction started.
transaction: this.transaction
},
// Add one entity key to the lookup request, with only one
// `path` element (i.e. no parent).
keys: [{ path: [{ kind: 'Trivia', name: 'hgtg' }] }]
}).execute((function(err, result) {
if (err) {
this.emit('error', {'rpc error': err});
return;
}
// Get the entity from the response if found.
if (result.found.length > 0) {
this.entity = result.found[0].entity;
}
this.commit();
}).bind(this));
};
/**
* Commit the transaction and an insert mutation if the entity was not
* found.
*/
Adams.prototype.commit = function() {
if (!this.entity) {
// If the entity is not found create it.
this.entity = {
// Set the entity key with only one `path` element (i.e. no parent).
key: { path: [{ kind: 'Trivia', name: 'hgtg' }] },
// Set the entity properties:
// - a utf-8 string: `question`
// - a 64bit integer: `answer`
properties: {
question: { stringValue: 'Meaning of life?' },
answer: { integerValue: 42 }
}
};
// Build a mutation to insert the new entity.
mutation = { insert: [this.entity] };
} else {
// No mutation if the entity was found.
mutation = null;
}
// Commit the transaction and the insert mutation if the entity was not found.
this.datastore.commit({
transaction: this.transaction,
mutation: mutation
}).execute((function(err, result) {
if (err) {
this.emit('error', err);
return;
}
this.ask();
}).bind(this));
};
/**
* Ask for the question and validate the answer.
*/
Adams.prototype.ask = function() {
// Get `question` property value.
var question = this.entity.properties.question.stringValue;
// Get `answer` property value.
var answer = this.entity.properties.answer.integerValue;
// Print the question and read one line from stdin.
this.readline.question(question + ' ', (function(result) {
this.readline.close();
// Validate the input against the entity answer property.
if (parseInt(result, 10) == answer) {
console.log('fascinating, extraordinary and, ',
'when you think hard about it, completely obvious.');
} else {
console.log("Don't panic!");
}
}).bind(this));
};
console.assert(process.argv.length == 3, 'usage: trivial.js <dataset-id>');
// Get the dataset ID from the command line parameters.
var demo = new Adams(process.argv[2]);
demo.once('error', function(err) {
console.error('Adams:', err);
process.exit(1);
});
With this example, you learned how to use the:
-
googleapis
package to connect to the Datastore API. -
beginTransaction
method to start a transaction. -
lookup
method to retrieve entities by key from your dataset. -
commit
method to send mutations to entities in your dataset and commit the transaction.
Now, you are ready to learn more about the Key Datastore Concepts and look at the JSON API reference .