Building a CRUD RESTful API with Cloud Functions and Firestore tutorial by Søren Spangsberg Jørgensen
Having a self created API allows me to hook up data to connect to front end pages, so I can feed information from the API to the page.
This tutorial is CRUD tutorial with firebase firestore and functions , so another item that I’m very interested in.
This is the video series where Søren Spangsberg Jørgensen goes through the setup/testing steps to get it running.
This is something interesting that will hopefully link up with some of the Static websites, being able to have an API up and running. This is also something that I have been wanting to do for a while and have been sidetracked down a lot of paths on the way.
As I was coding from the screen I made a few mistakes and it took me two days to get up and running, but I now have an operational localhost/postman workflow from the Tutorial. Now I need to adapt it to an expenses app.
Project process
I’ve setup the Firebase project, created a database (no data in it as yet)
Setup an App (no data) and used VS Studio to run a> firebase init and create a functions setup.
I’m now onto video 4 , having got the “Hello World” and initial test route & started the server on locval host to test. I’d done this thismorning and pushed to Github, the surface tablet had issues with linking to Github and I had to donload Git Bash on that pc and set up a new SSH key. Then I could push data to Github that I’ve now pulled on my laptop.
So on with Tut 4: This we’ll set up authentication between app and firebase firestore.
So setup authentication and add it to index.html. Generate a key , which is a json file, rename it something like “permissions.json” and put it in the functions folder of the project where the index.js file is and add its path to the index.js file:

const admin = require("firebase-admin");
const serviceAccount = require("./permissions.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://XXXXX.firebaseio.com",
});
Next, for the create function need the script and then test it in postman using the local host server up and running and adding the extended path http://localhost:5001/crudapi-2aee7/us-central1/app/api/create
This is something that confuses me. The functions are on a /us-central1 server whereas the database is Asia. I think I may need to just bang them all on a us server to keep them all in one place.

I couldn’t get the post (create to work, and tried putting it onto an Asia server, that didn’t work, so I’ve made a collection in the database and added a document to test a READ (get request).
I rebuilt a new project, the local host emulator recognises the permissions key so its authorised. See below:

I’m still getting timeout on the database, so no create or read functions still, even on deploy.
The problem:
I was not putting opening brackets around the asyc function and at the end })(); having the opening/closing brackets, which is a react thing and I think it activates the function. Anyway all done now, so I can get it all working.
So: I now have an active script that works with the firebase.firestore . I’ve also created an expenses database api. I’ve deployed the cloud functions and tested them, they are fine.
I was wondering how to get info out of database, but I can just do a read on the collection and then, in postman cut/paste JSON into a JSON/CSV converter to put into something else. Crude, but a simple backup. There are more sophisticated methods, but that will do for now. The code for the ttorial below for the index.js file in the Functions directory:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const serviceAccount = require("./permissions.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://crudapi3.firebaseio.com",
});
const db = admin.firestore();
console.log(db);
const express = require("express");
const app = express();
const cors = require("cors");
app.use(cors({ origin: true })); // this will allow it to go to another domain
//routes
app.get("/hw", (req, resp) => {
return resp.status(200).send("Hello World");
});
//crud
//create
app.post("/api/create", (req, resp) => {
(async () => {
try {
await db
.collection("product")
.doc("/" + req.body.id + "/")
.create({
name: req.body.name,
description: req.body.description,
price: req.body.price,
});
return resp.status(200).send(req.body.id + " added to db");
} catch (error) {
console.log(error);
console.log("this request did not work");
return resp.status(500).send(error);
}
})();
});
//read one doc
app.get("/api/read/:id", (req, resp) => {
(async () => {
try {
const document = db.collection("product").doc(req.params.id);
let product = await document.get();
let response = product.data();
return resp.status(200).send(response);
} catch (error) {
console.log(error);
console.log("this request did not work");
return resp.status(500).send(error);
}
})();
});
//read all docs
app.get("/api/read", (req, resp) => {
(async () => {
try {
let query = db.collection("product");
let response = [];
await query.get().then((querySnapshot) => {
let docs = querySnapshot.docs; // the result of the query
for (let doc of docs) {
const selectedItem = {
id: doc.id,
name: doc.data().name,
description: doc.data().description,
price: doc.data().price,
};
response.push(selectedItem);
}
return response; // each then should return a value
});
return resp.status(200).send(response);
} catch (error) {
console.log(error);
return resp.status(500).send(error);
}
return console.log("blah");
})();
});
//update. Put method
app.put("/api/update/:id", (req, resp) => {
(async () => {
try {
const document = db.collection("product").doc(req.params.id);
await document.update({
name: req.body.name,
description: req.body.description,
price: req.body.price,
});
return resp.status(200).send(req.body.id + "altered in db"); //req.body.id + "altered in db"
} catch (error) {
console.log(error);
console.log("this request did not work");
return resp.status(500).send(error);
}
})();
});
//delete
app.put("/api/delete/:id", (req, resp) => {
(async () => {
try {
const toDeleteId = req.params.id;
const document = db.collection("product").doc(req.params.id);
await document.delete();
return resp.status(200).send(toDeleteId + " deleted in db");
} catch (error) {
console.log(error);
console.log("this request did not work");
return resp.status(500).send(error);
}
})();
});
//export the api to the firebase cloud fnctions
exports.app = functions.https.onRequest(app);
End comment
That was hard yakka but I got there in the end. Two days messing with the code. I can now work on a front end interface for it, that’s another project.