Show Menu
Cheatography

Full Stack Dev With JS - Final Cheat Sheet (DRAFT) by

Full Stack Dev With JS - Final

This is a draft cheat sheet. It is a work in progress and is not finished yet.

Setup

React Client Setup
npm create vite@l­atest client -- --template react
 
cd client
 
npm install axios bootstrap react-­icons react-­rou­ter-dom
 
src > copy styles.css
 
src / app.jsx > import './sty­les.css'
Node/E­xpress Server setup
root > create a new folder named server
 
cd server
 
npm init -y
 
create server.js file
Concur­rently
root > npm i concur­rently
server > packag­e.json
"­scr­ipt­s": {
"­tes­t": "echo \"Error: no test specif­ied­\" && exit 1",
"­sta­rt": "node server.js­"
},
"­typ­e": "­mod­ule­"

root > packag­e.json
"­scr­ipt­s": {
"­sta­rt": "­con­cur­rently \"npm run server­\" \"npm run client­\"",
"­ser­ver­": "cd server && npm start",
"­cli­ent­": "cd client && npm run dev"
}

Client > src / config / api.js

export const API_BA­SE_URL = (impor­t.m­eta.en­v.V­ITE­_AP­I_B­ASE_URL || "­htt­p:/­/lo­cal­hos­t:3­000­"­).r­epl­ace­(/\/$/, "­");

export const API_URLS = {
books:
${API_­BAS­E_U­RL}­/books
,
book: (bookId) =>
${API_­BAS­E_U­RL}­/bo­oks­/${­bookId}
,
};

export const BOOKS_­API_URL = API_UR­LS.b­ooks;
export const getBookUrl = API_UR­LS.b­ook;

Client > main.jsx

import { StrictMode } from 'react'
import { createRoot } from 'react­-do­m/c­lient'
import './ind­ex.css'
import App from './App.jsx'
import {Brows­erR­outer as Router} from "­rea­ct-­rou­ter­-do­m"
import "­boo­tst­rap­/di­st/­css­/bo­ots­tra­p.c­ss"

create­Roo­t(d­ocu­men­t.g­etE­lem­ent­ByI­d('­roo­t')­).r­ender(
<St­ric­tMo­de>
<Ro­ute­r>
<App />
</R­out­er>
</S­tri­ctM­ode­>,
)

Client > App.jsx

import { BOOKS_­API­_URL, getBookUrl } from "./c­onf­ig/­api­";
import './sty­les.css';

const logError = (action, error) => {
consol­e.log(
ERROR in ${action}: ${erro­r.m­essage}
);
};

function App() {
const [books, setBooks] = useSta­te([]);

useEff­ect(() => {
const fetchBooks = async () => {
try {
const { data } = await axios.g­et­(BO­OKS­_AP­I_URL);
setBoo­ks(­data);
} catch (err) {
logErr­or(­"­fet­ching books", err);
}
};

fetchB­ooks();
}, []);

const handle­Delete = async (idToD­elete) => {
try {
await axios.d­el­ete­(ge­tBo­okU­rl(­idT­oDe­lete));
setBoo­ks(­(cu­rre­ntB­ooks) => curren­tBo­oks.fi­lte­r((­book) => book._id !== idToDe­lete));
} catch (err) {
logErr­or(­"­del­eting the book", err);
}
};

const handleAdd = async (newBook) => {
try {
const { data } = await axios.p­os­t(B­OOK­S_A­PI_URL, newBook);
setBoo­ks(­(cu­rre­ntB­ooks) => [...cu­rre­ntB­ooks, data]);
} catch (err) {
logErr­or(­"­adding the book", err);
}
};

const handle­Update = async (updat­edBook) => {
try {
const { data } = await axios.p­ut­(ge­tBo­okU­rl(­upd­ate­dBo­ok._­id), update­dBook);
setBoo­ks(­(cu­rre­ntB­ooks) => curren­tBo­oks.ma­p((­book) => (book._id === data._id ? data : book)));
} catch (err) {
logErr­or(­"­upd­ating the book", err);
}
};

const handle­Tog­gleLike = (bookT­oTo­ggle) => {
handle­Upd­ate({ ...boo­kTo­Toggle, like: !bookT­oTo­ggl­e.like });
};

return (
<div classN­ame­="Ap­p">
<NavBar />
<Header />
<Ro­ute­s>
<Route
path="/­"
elemen­t={­<Books books=­{books} onDele­te=­{ha­ndl­eDe­lete} onTogg­leL­ike­={h­and­leT­ogg­leLike} />}
/>
<Route path="/­add­boo­k" elemen­t={­<Ad­dBook onAdd=­{ha­ndl­eAdd} />} />
<Route path="/­upd­ate­boo­k/:­id" elemen­t={­<Up­dat­eBook onUpda­te=­{ha­ndl­eUp­date} />} />
</R­out­es>
<Footer />
</d­iv>
);
}

export default App;

Client > components / books.jsx

import Book from "./b­ook­";

const Books = ({ books = [], onDelete = (f) => f, onTogg­leLike = (f) => f }) => {
return (
<se­cti­on>
{!book­s.l­ength ? (
<h2­>There are no books availa­ble.</­h2>
) : (
<>
<h3­>Sh­owing {books.le­ngth} books.<­/h­3>
<table classN­ame­="ta­ble­">
<th­ead>
<tr>
<th­>Ti­tle­</t­h>
<th­>Au­tho­r</­th>
<th­>Number in Stock<­/th>
<th­>Pr­ice­</t­h>
<th­>Ra­tin­g</­th>
<th­>Pu­blish Year</­th>
<th­>Li­ke<­/th>
<th­>Ac­tio­ns(­s)<­/th>
</t­r>
</t­hea­d>
<tb­ody>
{books.ma­p((­book) => (
<Book key={b­ook._id} book={­book} onDele­te=­{on­Delete} onTogg­leL­ike­={o­nTo­ggl­eLike} />
))}
</t­bod­y>
</t­abl­e>
</>
)}
</s­ect­ion>
);
};

export default Books;

Client > components / book.jsx

import { FaHeart, FaRegH­eart, FaTrash, FaEdit } from "­rea­ct-­ico­ns/­fa";
import { Link } from "­rea­ct-­rou­ter­-do­m";

const Book = ({ book, onDelete = (f) => f, onTogg­leLike = (f) => f }) => {
const formatYear = () => {
return new Date(b­ook.pu­bli­shY­ear­).t­oIS­OSt­rin­g().sl­ice(0, 10);
};

return (
<tr>
<td­>{b­ook.ti­tle­}</­td>
<td­>{b­ook.au­tho­r}<­/td>
<td­>{b­ook.nu­mbe­rIn­Sto­ck}­</t­d>
<td­>{b­ook.pr­ice­}</­td>
<td­>{b­ook.ra­tin­g}<­/td>
<td­>{f­orm­atY­ear­()}­</t­d>
<td>
<button
type="b­utt­on"
classN­ame­="btn btn-link p-0 border­-0"
onClic­k={() => onTogg­leL­ike­(book)}
aria-l­abe­l={­boo­k.like ? "­Unlike book" : "Like book"}
>
{book.like ? <Fa­Heart color=­"­red­" /> : <Fa­Reg­Heart />}
</b­utt­on>
</t­d>
<td>
<Link to={
/updat­ebo­ok/­${b­ook._id}
}>
<FaEdit />
</L­ink>
</t­d>
<td>
<Fa­Trash onClic­k={() => onDele­te(­boo­k._id)} />
</t­d>
</t­r>
);
};

export default Book;

Client > components / addBoo­k.jsx

import { useState } from "­rea­ct";
import { useNav­igate } from "­rea­ct-­rou­ter­-do­m";
const AddBook = ({ onAdd = (f) => f }) => {
const [book, setBook] = useState({
title: "­",
author: "­",
number­InS­tock: "­",
price: "­",
rating: "­",
publis­hYear: "­",
like: "­",
});
const navigate = useNav­iga­te();
const submitForm = (e) => {
e.prev­ent­Def­ault();
onAdd(­book);
setBook({
title: "­",
author: "­",
number­InS­tock: "­",
price: "­",
rating: "­",
publis­hYear: "­",
like: "­",
});
naviga­te(­"­/");
};

return (
<di­v>
<h1­>Please enter the details of the new Book here..<­/h­1>
<form onSubm­it=­{su­bmi­tForm} method­="po­st">
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="t­itl­e" classN­ame­="p-­3">
Book Title
</l­abe­l>
<input
type="t­ext­"
name="t­itl­e"
id="­tit­le"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Title"
onChan­ge=­{(e­vent) => setBook({ ...book, title: event.t­ar­get.value })}
value=­{bo­ok.t­itle}
required
/>
</d­iv>

<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="a­uth­or" classN­ame­="p-­3">
Book Author
</l­abe­l>
<input
type="t­ext­"
name="a­uth­or"
id="­aut­hor­"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter an Author­"
onChan­ge=­{(e­vent) => setBook({ ...book, author: event.t­ar­get.value })}
value=­{bo­ok.a­uthor}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="n­umb­erI­nSt­ock­" classN­ame­="p-­3">
Number In Stock
</l­abe­l>
<input
type="n­umb­er"
name="n­umb­erI­nSt­ock­"
id="­num­ber­InS­toc­k"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Number In Stock"
onChan­ge=­{(e­vent) => setBook({ ...book, number­InS­tock: event.t­ar­get.value })}
value=­{bo­ok.n­um­ber­InS­tock}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="p­ric­e" classN­ame­="p-­3">
Book Price
</l­abe­l>
<input
type="t­ext­"
name="p­ric­e"
id="­pri­ce"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Price"
onChan­ge=­{(e­vent) => setBook({ ...book, price: event.t­ar­get.value })}
value=­{bo­ok.p­rice}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="r­ati­ng" classN­ame­="p-­3">
Book Rating
</l­abe­l>
<input
type="n­umb­er"
name="r­ati­ng"
id="­rat­ing­"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Rating­"
onChan­ge=­{(e­vent) => setBook({ ...book, rating: event.t­ar­get.value })}
value=­{bo­ok.r­ating}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="p­ubl­ish­Yea­r" classN­ame­="p-­3">
Book Publish Year
</l­abe­l>
<input
type="d­ate­"
name="p­ubl­ish­Yea­r"
id="­pub­lis­hYe­ar"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Publish Year"
onChan­ge=­{(e­vent) => setBook({ ...book, publis­hYear: event.t­ar­get.value })}
value=­{bo­ok.p­ub­lis­hYear}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label classN­ame­="p-3 d-bloc­k">
Like Status (True/­False)
</l­abe­l>
<div classN­ame­="fo­rm-­check form-c­hec­k-i­nli­ne">
<input
type="r­adi­o"
name="l­ike­"
id="­lik­e-t­rue­"
classN­ame­="fo­rm-­che­ck-­inp­ut"
checke­d={­boo­k.like === true}
onChan­ge={() => setBook({ ...book, like: true })}
required
/>
<label htmlFo­r="l­ike­-tr­ue" classN­ame­="fo­rm-­che­ck-­lab­el">
True
</l­abe­l>
</d­iv>
<div classN­ame­="fo­rm-­check form-c­hec­k-i­nli­ne">
<input
type="r­adi­o"
name="l­ike­"
id="­lik­e-f­als­e"
classN­ame­="fo­rm-­che­ck-­inp­ut"
checke­d={­boo­k.like === false}
onChan­ge={() => setBook({ ...book, like: false })}
required
/>
<label htmlFo­r="l­ike­-fa­lse­" classN­ame­="fo­rm-­che­ck-­lab­el">
False
</l­abe­l>
</d­iv>
</d­iv>

<button classN­ame­="m-5 p-3 w-25">ADD THE BOOK</­but­ton>
</f­orm>
</d­iv>
);
};

export default AddBook;

Client > components / update­Boo­k.jsx

import { getBookUrl } from "../­con­fig­/ap­i";

const UpdateBook = ({ onUpdate = (f) => f }) => {
const [book, setBook] = useState({
title: "­",
author: "­",
number­InS­tock: "­",
price: "­",
rating: "­",
publis­hYear: "­",
like: "­",
});
const { id } = usePar­ams();
useEff­ect(() => {
const fetchData = async () => {
try {
const { data } = await axios.g­et­(ge­tBo­okU­rl(­id));
const date = new Date(d­ata.pu­bli­shY­ear­).t­oIS­OSt­rin­g().sl­ice(0, 10);
setBook({ ...data, publis­hYear: date }); //data is the existing book in the DB
} catch (err) {
consol­e.log(
There is an ERROR in fetching ${err.m­es­sage}
);
}
};
fetchD­ata();
return () => {
//clean up
};
}, [id]);
const navigate = useNav­iga­te();
const submitForm = (e) => {
e.prev­ent­Def­ault();
onUpda­te(­book);
setBook({
title: "­",
author: "­",
number­InS­tock: "­",
price: "­",
rating: "­",
publis­hYear: "­",
like: "­",
});
naviga­te(­"­/");
};

return (
<di­v>
<h1­>Please enter the details of the updated Book here..<­/h­1>
<form onSubm­it=­{su­bmi­tForm} method­="po­st">
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="t­itl­e" classN­ame­="p-­3">
Book Title
</l­abe­l>
<input
type="t­ext­"
name="t­itl­e"
id="­tit­le"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Title"
onChan­ge=­{(e­vent) => setBook({ ...book, title: event.t­ar­get.value })}
value=­{bo­ok.t­itle}
required
/>
</d­iv>

<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="a­uth­or" classN­ame­="p-­3">
Book Author
</l­abe­l>
<input
type="t­ext­"
name="a­uth­or"
id="­aut­hor­"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter an Author­"
onChan­ge=­{(e­vent) => setBook({ ...book, author: event.t­ar­get.value })}
value=­{bo­ok.a­uthor}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="n­umb­erI­nSt­ock­" classN­ame­="p-­3">
Number In Stock
</l­abe­l>
<input
type="n­umb­er"
name="n­umb­erI­nSt­ock­"
id="­num­ber­InS­toc­k"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Number In Stock"
onChan­ge=­{(e­vent) => setBook({ ...book, number­InS­tock: event.t­ar­get.value })}
value=­{bo­ok.n­um­ber­InS­tock}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="p­ric­e" classN­ame­="p-­3">
Book Price
</l­abe­l>
<input
type="t­ext­"
name="p­ric­e"
id="­pri­ce"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Price"
onChan­ge=­{(e­vent) => setBook({ ...book, price: event.t­ar­get.value })}
value=­{bo­ok.p­rice}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="r­ati­ng" classN­ame­="p-­3">
Book Rating
</l­abe­l>
<input
type="n­umb­er"
name="r­ati­ng"
id="­rat­ing­"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Rating­"
onChan­ge=­{(e­vent) => setBook({ ...book, rating: event.t­ar­get.value })}
value=­{bo­ok.r­ating}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label htmlFo­r="p­ubl­ish­Yea­r" classN­ame­="p-­3">
Book Publish Year
</l­abe­l>
<input
type="d­ate­"
name="p­ubl­ish­Yea­r"
id="­pub­lis­hYe­ar"
classN­ame­="fo­rm-­con­tro­l"
placeh­old­er=­"­Enter a Publish Year"
onChan­ge=­{(e­vent) => setBook({ ...book, publis­hYear: event.t­ar­get.value })}
value=­{bo­ok.p­ub­lis­hYear}
required
/>
</d­iv>
<div classN­ame­="fo­rm-­gro­up">
<label classN­ame­="p-3 d-bloc­k">Like Status (True/­Fal­se)­</l­abe­l>
<div classN­ame­="fo­rm-­check form-c­hec­k-i­nli­ne">
<input
type="r­adi­o"
name="l­ike­"
id="­lik­e-t­rue­"
classN­ame­="fo­rm-­che­ck-­inp­ut"
checke­d={­boo­k.like === true}
onChan­ge={() => setBook({ ...book, like: true })}
required
/>
<label htmlFo­r="l­ike­-tr­ue" classN­ame­="fo­rm-­che­ck-­lab­el">
True
</l­abe­l>
</d­iv>
<div classN­ame­="fo­rm-­check form-c­hec­k-i­nli­ne">
<input
type="r­adi­o"
name="l­ike­"
id="­lik­e-f­als­e"
classN­ame­="fo­rm-­che­ck-­inp­ut"
checke­d={­boo­k.like === false}
onChan­ge={() => setBook({ ...book, like: false })}
required
/>
<label htmlFo­r="l­ike­-fa­lse­" classN­ame­="fo­rm-­che­ck-­lab­el">
False
</l­abe­l>
</d­iv>
</d­iv>

<button classN­ame­="m-5 p-3 w-25">U­PDATE THE BOOK</­but­ton>
</f­orm>
</d­iv>
);
};

export default Update­Book;

Client > navBar.jsx

import { Link } from "­rea­ct-­rou­ter­-do­m";
const NavBar = () => {
return (
<nav classN­ame­="navbar navbar­-ex­pand-lg navbar­-light bg-lig­ht">
<div classN­ame­="co­llapse navbar­-co­lla­pse­" id="­nav­bar­Nav­">
<ul classN­ame­="na­vba­r-n­av">
<li classN­ame­="na­v-item active­">
<Link classN­ame­="na­v-l­ink­" to="­/">
My Book Library
</L­ink>
</l­i>
<li classN­ame­="na­v-i­tem­">
<Link classN­ame­="na­v-l­ink­" to="­/">
Books
</L­ink>
</l­i>

<li classN­ame­="na­v-i­tem­">
<Link classN­ame­="na­v-l­ink­" to="­add­boo­k">
Add a Book
</L­ink>
</l­i>
</u­l>
</d­iv>
</n­av>
);
};

export default NavBar;
 

Server > config / db.js

import mongoose from "­mon­goo­se";
import { url } from "../­atl­as_­uri.js­";

export const connectDB = async () => {
try {
await mongoo­se.c­on­nec­t(url);
consol­e.l­og(­"­Con­nected to DB");
} catch (err) {
consol­e.log(
ERROR in connec­ting: ${err.m­es­sage}
);
proces­s.e­xit(1); //exit in case of failure
}
};
export const discon­nectDB = async () => {
await mongoo­se.c­on­nec­tio­n.c­lose();
consol­e.l­og(­"­Con­nection closed­");
};

Server > models / books.js

import mongoose from "­mon­goo­se";

const bookSchema = new mongoo­se.S­ch­ema({
title: {
type: String,
required: [true, "­Please check your entry, no title specif­ied."],
},
author: {
type: String,
required: [true, "­Please check your entry, no author specif­ied."],
},
number­InS­tock: {
type: Number,
required: [true, "­Number in Stock is missing. Please provide a value."­],
},
price: Number,
rating: {
type: Number,
min: 1,
max: 10,
required: [true, "The rating is required, please specify a value between 1-100."­],
},
publis­hYear: {
type: Date,
default: Date.now, // No parent­heses to ensure execution at creation time
},
like: Boolean,
});

export const Book = mongoo­se.m­od­el(­"­Boo­k", bookSc­hema);

Server > server.js

import express from "­exp­res­s";
import { connectDB } from "./c­onf­ig/­db.j­s";
import router from "./r­out­es/­bas­icR­out­es.j­s";
import cors from "­cor­s";

//1. create an express applic­ation
const app = express();

//2. set up all the middle­wares
app.us­e(e­xpr­ess.ur­len­coded({ extended: true }));
app.us­e(e­xpr­ess.js­on());
app.us­e(e­xpr­ess.st­ati­c("p­ubl­ic"));
app.us­e(c­ors());

//3. connect to the database
connec­tDB();

//4. set up the routes
app.us­e("/­", router);

//5. make your server listen to port 3000
const PORT = proces­s.e­nv.PORT || 3000;
app.li­ste­n(PORT, () => {
consol­e.log(
The server is up and listening on PORT${­PORT}
);
});

Server > routes / basicR­out­es.js

import express from "­exp­res­s";
import { Book } from "../­mod­els­/bo­oks.js­";

const router = expres­s.R­out­er();

//GET ALL BOOKS - READ OPERATION
router.ge­t("/­boo­ks", async (req, res) => {
try {
const books = await Book.f­ind();
if (books.length === 0) {
return res.st­atu­s(4­04).json({ error: "­There are no books."­ });
}
res.js­on(­books);
} catch (err) {
//500 --> Internal Server Error
res.st­atu­s(5­00).json({ error: err.me­ssage });
}
});

//GET ONE BOOK - READ OPERATION
router.ge­t("/­boo­ks/­:id­", async (req, res) => {
const { id } = req.pa­rams;
try {
// const book = await Book.f­ind­ByI­d(id);
// const book = await Book.f­ind­One­({"t­itl­e":"E­loquent JavaSc­rip­t"});
const book = await Book.f­ind­One({ _id: id });
if (!book) {
return res.st­atu­s(4­04).json({ error: "­There are no such book." });
}
res.js­on(­book);
} catch (err) {
//500 --> Internal Server Error
res.st­atu­s(5­00).json({ error: err.me­ssage });
}
});

//POST BOOK - CREATE OPERATION
router.po­st(­"­/bo­oks­", async (req, res) => {
try {
const book = new Book(r­eq.b­ody);
const savedBook = await book.s­ave();
res.st­atu­s(2­01).js­on(­sav­edB­ook);
} catch (err) {
//500 --> Internal Server Error
res.st­atu­s(5­00).json({ error: err.me­ssage });
}
});

//PUT BOOK - UPDATE OPERATION
router.pu­t("/­boo­ks/­:id­", async (req, res) => {
const { id } = req.pa­rams;
try {
const upatedBook = await Book.f­ind­ByI­dAn­dUp­dat­e(id, req.body, { new: true, runVal­ida­tors: true });
if (!upat­edBook) {
return res.st­atu­s(4­04).json({ error: "­There are no such book." });
}
res.js­on(­upa­ted­Book);
} catch (err) {
//500 --> Internal Server Error
res.st­atu­s(5­00).json({ error: err.me­ssage });
}
});

//DELETE BOOK - DELETE OPERATION
router.de­let­e("/­boo­ks/­:id­", async (req, res) => {
const { id } = req.pa­rams;
try {
const delete­dBook = await Book.f­ind­ByI­dAn­dDe­let­e(id);
if (!dele­ted­Book) {
return res.st­atu­s(4­04).json({ error: "­There are no such book." });
}
res.js­on(­del­ete­dBook);
} catch (err) {
//500 --> Internal Server Error
res.st­atu­s(5­00).json({ error: err.me­ssage });
}
});
export default router;