databases/hello-app-cloud-spanner/src/server.js (95 lines of code) (raw):
/*
Copyright 2023 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
https://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.
*/
(async () => {
const crypto = require('crypto');
const express = require("express");
const path = require('path');
const cors = require('cors');
const port = process.env.PORT || 8080;
const app = express();
app.use(cors(), express.json(), express.static(path.resolve(__dirname, '../client/build')));
// Configures the Cloud Spanner client
const { Spanner } = require('@google-cloud/spanner');
const spanner = new Spanner({ projectId: process.env.GOOGLE_CLOUD_PROJECT_ID });
const instance = spanner.instance(process.env.CLOUD_SPANNER_INSTANCE || 'hello-instance');
const database = instance.database(process.env.CLOUD_SPANNER_DATABASE || 'hello-database');
// Retrieves the database dialect
await database.getMetadata();
const isPostgreSQLDialect = database.metadata.databaseDialect === "POSTGRESQL";
//Get all players
app.get("/api/v1/players", async (req, res) => {
const [rows] = await database.run("SELECT * FROM Players");
res.send(rows);
});
// Insert a player (warning: no validation is done)
app.post("/api/v1/players", async (req, res) => {
const { firstName, lastName, birthDate } = req.body;
const uuid = crypto.randomUUID();
database.runTransaction(async (error, transaction) => {
if (error) {
res.status(500).send({ error: error.details });
return;
}
try {
if (isPostgreSQLDialect) {
await transaction.runUpdate({
sql: `INSERT INTO Players
(PlayerUuid, FirstName, LastName, BirthDate)
VALUES ($1, $2, $3, $4)`,
params: {
p1: uuid,
p2: firstName,
p3: lastName,
p4: new Date(birthDate)
}
});
} else {
await transaction.runUpdate({
sql: `INSERT INTO Players
(PlayerUuid, FirstName, LastName, BirthDate)
VALUES (@playerUuid, @firstName, @lastName, @birthDate)`,
params: {
playerUuid: uuid,
firstName,
lastName,
birthDate
}
});
}
await transaction.commit();
res.status(201).send({
PlayerUuid: uuid,
FirstName: firstName,
LastName: lastName,
BirthDate: birthDate
});
} catch (error) {
res.status(500).send({ error: error.details });
}
});
});
// Deletes a given player (warning: no validation is done)
app.delete("/api/v1/players/:uuid", async (req, res) => {
const uuid = req.params.uuid;
database.runTransaction(async (error, transaction) => {
if (error) {
res.status(500).send({ error: error.details });
return;
}
try {
if (isPostgreSQLDialect) {
await transaction.runUpdate({
sql: `DELETE FROM Players WHERE PlayerUuid = $1`,
params: { p1: uuid }
});
} else {
await transaction.runUpdate({
sql: `DELETE FROM Players WHERE PlayerUuid = @playerUuid`,
params: { playerUuid: uuid }
});
}
await transaction.commit();
res.status(204).send();
} catch (error) {
res.status(500).send({ error: error.details });
}
});
});
app.get("*", (_req, res) => {
res.sendFile(path.resolve(__dirname, "../client/build", "index.html"));
});
//Start the server
app.listen(port, () => console.log(`App listening on port ${port}!`))
})();