├── .babelrc ├── .gitattributes ├── firebase.js ├── models └── productModel.js ├── index.js ├── routes └── productRoute.js ├── package.json ├── config.js ├── .gitignore └── controllers └── productController.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env"]] 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /firebase.js: -------------------------------------------------------------------------------- 1 | import { initializeApp } from 'firebase/app'; 2 | import config from './config.js'; 3 | 4 | const firebase = initializeApp(config.firebaseConfig); 5 | 6 | export default firebase; 7 | -------------------------------------------------------------------------------- /models/productModel.js: -------------------------------------------------------------------------------- 1 | class Product { 2 | constructor(id, name, price, retailer, amountInStock) { 3 | (this.id = id), 4 | (this.name = name), 5 | (this.price = price), 6 | (this.retailer = retailer), 7 | (this.amountInStock = amountInStock); 8 | } 9 | } 10 | 11 | export default Product; 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import cors from 'cors'; 3 | 4 | import config from './config.js'; 5 | import productRoute from './routes/productRoute.js'; 6 | 7 | const app = express(); 8 | 9 | app.use(cors()); 10 | app.use(express.json()); 11 | 12 | //routes 13 | app.use('/api', productRoute); 14 | 15 | app.listen(config.port, () => 16 | console.log(`Server is live @ ${config.hostUrl}`), 17 | ); 18 | -------------------------------------------------------------------------------- /routes/productRoute.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | import { 4 | createProduct, 5 | getProduct, 6 | getProducts, 7 | updateProduct, 8 | deleteProduct, 9 | } from '../controllers/productController.js'; 10 | 11 | const router = express.Router(); 12 | 13 | router.get('/', getProducts); 14 | router.post('/new', createProduct); 15 | router.get('/product/:id', getProduct); 16 | router.put('/update/:id', updateProduct); 17 | router.delete('/delete/:id', deleteProduct); 18 | 19 | export default router; 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start": "nodemon index.js" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.0.3", 17 | "express": "^4.18.2", 18 | "firebase": "^9.19.1" 19 | }, 20 | "devDependencies": { 21 | "@babel/cli": "^7.21.0", 22 | "@babel/core": "^7.21.4", 23 | "@babel/node": "^7.20.7", 24 | "@babel/preset-env": "^7.21.4", 25 | "nodemon": "^2.0.22" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | import assert from 'assert'; 3 | 4 | dotenv.config(); 5 | 6 | const { 7 | PORT, 8 | HOST, 9 | HOST_URL, 10 | API_KEY, 11 | AUTH_DOMAIN, 12 | PROJECT_ID, 13 | STORAGE_BUCKET, 14 | MESSAGING_SENDER_ID, 15 | APP_ID, 16 | } = process.env; 17 | 18 | assert(PORT, 'Port is required'); 19 | assert(HOST, 'Host is required'); 20 | 21 | export default { 22 | port: PORT, 23 | host: HOST, 24 | hostUrl: HOST_URL, 25 | firebaseConfig: { 26 | apiKey: API_KEY, 27 | authDomain: AUTH_DOMAIN, 28 | projectId: PROJECT_ID, 29 | storageBucket: STORAGE_BUCKET, 30 | messagingSenderId: MESSAGING_SENDER_ID, 31 | appId: APP_ID, 32 | }, 33 | }; 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Serverless directories 108 | .serverless/ 109 | 110 | # FuseBox cache 111 | .fusebox/ 112 | 113 | # DynamoDB Local files 114 | .dynamodb/ 115 | 116 | # TernJS port file 117 | .tern-port 118 | 119 | # Stores VSCode versions used for testing VSCode extensions 120 | .vscode-test 121 | 122 | # yarn v2 123 | .yarn/cache 124 | .yarn/unplugged 125 | .yarn/build-state.yml 126 | .yarn/install-state.gz 127 | .pnp.* 128 | -------------------------------------------------------------------------------- /controllers/productController.js: -------------------------------------------------------------------------------- 1 | import firebase from '../firebase.js'; 2 | import Product from '../models/productModel.js'; 3 | import { 4 | getFirestore, 5 | collection, 6 | doc, 7 | addDoc, 8 | getDoc, 9 | getDocs, 10 | updateDoc, 11 | deleteDoc, 12 | } from 'firebase/firestore'; 13 | 14 | const db = getFirestore(firebase); 15 | 16 | //create new product 17 | 18 | export const createProduct = async (req, res, next) => { 19 | try { 20 | const data = req.body; 21 | await addDoc(collection(db, 'products'), data); 22 | res.status(200).send('product created successfully'); 23 | } catch (error) { 24 | res.status(400).send(error.message); 25 | } 26 | }; 27 | 28 | //get get all products 29 | 30 | export const getProducts = async (req, res, next) => { 31 | try { 32 | const products = await getDocs(collection(db, 'products')); 33 | const productArray = []; 34 | 35 | if (products.empty) { 36 | res.status(400).send('No Products found'); 37 | } else { 38 | products.forEach((doc) => { 39 | const product = new Product( 40 | doc.id, 41 | doc.data().name, 42 | doc.data().price, 43 | doc.data().retailer, 44 | doc.data().amountInStock, 45 | ); 46 | productArray.push(product); 47 | }); 48 | 49 | res.status(200).send(productArray); 50 | } 51 | } catch (error) { 52 | res.status(400).send(error.message); 53 | } 54 | }; 55 | 56 | //get product by id 57 | 58 | export const getProduct = async (req, res, next) => { 59 | try { 60 | const id = req.params.id; 61 | const product = doc(db, 'products', id); 62 | const data = await getDoc(product); 63 | if (data.exists()) { 64 | res.status(200).send(data.data()); 65 | } else { 66 | res.status(404).send('product not found'); 67 | } 68 | } catch (error) { 69 | res.status(400).send(error.message); 70 | } 71 | }; 72 | 73 | //update product (with id) 74 | 75 | export const updateProduct = async (req, res, next) => { 76 | try { 77 | const id = req.params.id; 78 | const data = req.body; 79 | const product = doc(db, 'products', id); 80 | await updateDoc(product, data); 81 | res.status(200).send('product updated successfully'); 82 | } catch (error) { 83 | res.status(400).send(error.message); 84 | } 85 | }; 86 | 87 | //delete product (with id) 88 | 89 | export const deleteProduct = async (req, res, next) => { 90 | try { 91 | const id = req.params.id; 92 | await deleteDoc(doc(db, 'products', id)); 93 | res.status(200).send('product deleted successfully'); 94 | } catch (error) { 95 | res.status(400).send(error.message); 96 | } 97 | }; 98 | --------------------------------------------------------------------------------