├── .gitignore ├── package-lock.json ├── package.json ├── src ├── config │ └── firebase.config.ts ├── controllers │ ├── cities-crud.controller.ts │ ├── crud.controller.ts │ └── upload-file.controller.ts └── server.ts ├── tsconfig.json └── views └── index.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | dist/ 3 | .vscode 4 | node_modules 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js", 9 | "dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/server.js\"" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "body-parser": "^1.20.1", 15 | "concurrently": "^7.6.0", 16 | "dotenv": "^16.0.3", 17 | "ejs": "^3.1.8", 18 | "express": "^4.18.2", 19 | "firebase": "^9.16.0", 20 | "lodash": "^4.17.21", 21 | "multer": "^1.4.5-lts.1" 22 | }, 23 | "devDependencies": { 24 | "@types/express": "^4.17.16", 25 | "@types/mongoose": "^5.11.97", 26 | "@types/multer": "^1.4.7", 27 | "@types/node": "^18.11.18", 28 | "nodemon": "^2.0.20", 29 | "ts-node": "^10.9.1", 30 | "typescript": "^4.9.5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config/firebase.config.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | dotenv.config(); 3 | 4 | export default { 5 | firebaseConfig: { 6 | apiKey: process.env.API_KEY, 7 | authDomain: process.env.AUTH_DOMAIN, 8 | projectId: process.env.PROJECT_ID, 9 | databaseURL: process.env.FIRESTORE_DB_URL, 10 | storageBucket: process.env.STORAGE_BUCKET, 11 | messagingSenderId: process.env.MESSAGING_SENDER_ID, 12 | appId: process.env.APP_ID, 13 | measurementId: process.env.MEASUREMENT_ID, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/controllers/cities-crud.controller.ts: -------------------------------------------------------------------------------- 1 | import { initializeApp } from "firebase/app"; 2 | import { addDoc, collection, doc, getDocs, getFirestore, query, where, documentId, setDoc } from "firebase/firestore"; 3 | import config from "../config/firebase.config" 4 | import { pick } from "lodash"; 5 | import express, { Router, Request, Response } from "express"; 6 | const router: Router = express.Router(); 7 | 8 | // Initialize Firebase 9 | const app = initializeApp(config.firebaseConfig); 10 | 11 | // Initialize Cloud Firestore and get a reference to the service 12 | const db = getFirestore(app); 13 | 14 | // Get reference to employee collection 15 | const cityRef = collection(db, "cities"); 16 | 17 | // Add new data 18 | router.post('/', async (req: Request, res: Response) => { 19 | try { 20 | const city = pick(req.body, ['name', 'state', 'country']); 21 | const docRef = await addDoc(cityRef, city); 22 | console.log("Document written with ID: ", docRef.id); 23 | return res.send('New City added to DB.') 24 | } catch (e) { 25 | return res.status(400).send(e.message) 26 | } 27 | }) 28 | 29 | export default router; -------------------------------------------------------------------------------- /src/controllers/crud.controller.ts: -------------------------------------------------------------------------------- 1 | import { initializeApp } from "firebase/app"; 2 | import { addDoc, collection, doc, getDocs, getFirestore, query, where, documentId, setDoc, updateDoc, deleteDoc } from "firebase/firestore"; 3 | import config from "../config/firebase.config" 4 | import { pick } from "lodash"; 5 | import express, { Router, Request, Response } from "express"; 6 | const router: Router = express.Router(); 7 | 8 | // Initialize Firebase 9 | const app = initializeApp(config.firebaseConfig); 10 | 11 | // Initialize Cloud Firestore and get a reference to the service 12 | const db = getFirestore(app); 13 | 14 | // Get reference to employee collection 15 | const employeesRef = collection(db, "employee"); 16 | 17 | //Add new Employee 18 | router.post('/', async (req: Request, res: Response) => { 19 | try { 20 | const employee = pick(req.body, ['name', 'age', 'position', 'isPermanent']); 21 | const docRef = await addDoc(employeesRef, employee); 22 | console.log("Document written with ID: ", docRef.id); 23 | return res.send('New employee added to DB.') 24 | } catch (e) { 25 | return res.status(400).send(e.message) 26 | } 27 | }) 28 | 29 | //Get records of all employees 30 | router.get('/', async (req: Request, res: Response) => { 31 | try { 32 | const querySnapshot = await getDocs(employeesRef); 33 | const records = []; 34 | querySnapshot.forEach((doc) => { 35 | // doc.data() is never undefined for query doc snapshots 36 | records.push(doc.data()); 37 | }); 38 | return res.send({ 39 | 'employees records': records 40 | }); 41 | } catch (err) { 42 | res.status(400).send(err.message); 43 | } 44 | }) 45 | 46 | // Get employee by Id 47 | router.get('/:id', async (req: Request, res: Response) => { 48 | try { 49 | const employeeId = req.params.id 50 | 51 | const q = query(employeesRef, where(documentId(), "==", employeeId)); 52 | // const q = query(employeesRef, where("isPermanent", "==", true)); 53 | 54 | const querySnapshot = await getDocs(q); 55 | if (querySnapshot.empty) { 56 | return res.send(`Employee with id ${employeeId} does not exists.`) 57 | } 58 | const employeeRecord = querySnapshot.docs[0].data(); 59 | res.send({ 60 | 'Employee record': employeeRecord 61 | }) 62 | } catch (error) { 63 | res.status(400).send(error.message) 64 | } 65 | }) 66 | 67 | // edit employee records 68 | router.put('/:id', async (req: Request, res: Response) => { 69 | try { 70 | const employeeId = req.params.id; 71 | const UpdatedEmployee = pick(req.body, ['name', 'age', 'position', 'isPermanent']); 72 | const q = query(employeesRef, where(documentId(), "==", employeeId)); 73 | const querySnapshot = await getDocs(q); 74 | if (querySnapshot.empty) { 75 | return res.send(`Employee with id ${employeeId} does not exists.`) 76 | } 77 | //updateDoc can update single or multiple fields 78 | await updateDoc(doc(db, "employee", employeeId), UpdatedEmployee); 79 | res.send('Employee record edited.') 80 | } catch (error) { 81 | res.status(400).send(error.message) 82 | } 83 | }) 84 | 85 | // Delete employee records 86 | router.delete('/:id', async (req: Request, res: Response) => { 87 | try { 88 | const employeeId = req.params.id; 89 | const querySnapshot = await getDocs(query(employeesRef, where(documentId(), "==", employeeId))); 90 | if (querySnapshot.empty) { 91 | return res.send(`Employee with id ${employeeId} does not exists.`) 92 | } 93 | //deleteDoc delete a document if exists 94 | await deleteDoc(doc(db, "employee", employeeId)); 95 | res.send('Employee records Deleted.') 96 | } catch (error) { 97 | res.status(400).send(error.message) 98 | } 99 | }) 100 | 101 | export default router; -------------------------------------------------------------------------------- /src/controllers/upload-file.controller.ts: -------------------------------------------------------------------------------- 1 | import express, { Router } from "express"; 2 | import { initializeApp } from "firebase/app"; 3 | import { getStorage, ref, getDownloadURL, uploadBytesResumable } from "firebase/storage"; 4 | import multer from "multer"; 5 | import config from "../config/firebase.config" 6 | 7 | const router: Router = express.Router(); 8 | 9 | //Initialize a firebase application 10 | initializeApp(config.firebaseConfig); 11 | 12 | // Initialize Cloud Storage and get a reference to the service 13 | const storage = getStorage(); 14 | 15 | // Setting up multer as a middleware to grab photo uploads 16 | const upload = multer({ storage: multer.memoryStorage() }); 17 | 18 | router.post("/", upload.single("filename"), async (req, res) => { 19 | try { 20 | const dateTime = giveCurrentDateTime(); 21 | 22 | const storageRef = ref(storage, `files/${req.file.originalname + " " + dateTime}`); 23 | 24 | // Create file metadata including the content type 25 | const metadata = { 26 | contentType: req.file.mimetype, 27 | }; 28 | 29 | // Upload the file in the bucket storage 30 | const snapshot = await uploadBytesResumable(storageRef, req.file.buffer, metadata); 31 | //by using uploadBytesResumable we can control the progress of uploading like pause, resume, cancel 32 | 33 | // Grab the public url 34 | const downloadURL = await getDownloadURL(snapshot.ref); 35 | 36 | console.log('File successfully uploaded.'); 37 | return res.send({ 38 | message: 'file uploaded to firebase storage', 39 | name: req.file.originalname, 40 | type: req.file.mimetype, 41 | downloadURL: downloadURL 42 | }) 43 | } catch (error) { 44 | return res.status(400).send(error.message) 45 | } 46 | }); 47 | 48 | const giveCurrentDateTime = () => { 49 | const today = new Date(); 50 | const date = today.getFullYear() + '-' + (today.getMonth() + 1) + '-' + today.getDate(); 51 | const time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds(); 52 | const dateTime = date + ' ' + time; 53 | return dateTime; 54 | } 55 | 56 | export default router; -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import express, { Express } from "express"; 2 | import uploadRouter from "./controllers/upload-file.controller"; 3 | import employeeRouter from "./controllers/crud.controller"; 4 | import cityRouter from "./controllers/cities-crud.controller"; 5 | import bodyParser from "body-parser"; 6 | import * as dotenv from 'dotenv' 7 | dotenv.config(); 8 | 9 | const app: Express = express(); 10 | app.set('view engine', 'ejs'); 11 | 12 | app.use(bodyParser.json()); 13 | app.use(bodyParser.urlencoded({ 14 | extended: false 15 | })); 16 | 17 | app.get('/', (req, res) => { 18 | res.send('Firebase demo App of nodejs-db-demo Project.') 19 | }) 20 | 21 | app.use('/upload', uploadRouter); 22 | app.use('/employee', employeeRouter); 23 | app.use('/city', cityRouter); 24 | 25 | const port = process.env.PORT || 3000; 26 | app.listen(port, () => { 27 | console.log(`Server is listening at port ${port}`); 28 | }) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", //directory for all js files / output files 4 | "rootDir": "./src", //directory for all TS files / source files 5 | "target": "ES6", 6 | "watch": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | // "noImplicitAny": true, 11 | "removeComments": true, 12 | "preserveConstEnums": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Firebase demo App 8 | 9 | 10 |

Firebase demo App

11 | 12 | 13 | --------------------------------------------------------------------------------