Jonas – Node.js part 1
Download here: https://nodejs.org/en/. Install. Check in command line node -v.
Section 1 – Intro
File I/O. Asynchronous non blocking. Pay attention to 2 different functions readFileSync vs readFile.
Simple server request and response.

file path: . refers to where nodejs is run/started, ${__dirname} refers to where the scirpt is located
Prepare placeholders in html template, to insert data (probably they do not need to even in brackets {} or %, just any uniquely identified string will do, because we will replace them like any text with .replace function)

Modular dev


dependencies, required for the app, install –save.
devDependencies, tools for development, not the app, install –save-dev
install across all projects in your machine (usually for devDep), npm i package –global

npm outdated, find outdated packages
npm install slugify@1.0.0, install past version, 1.0.0
before versino number: ^ accept minor, ~ accept only bug patches, * all versions
npm update slugify, update a package
npm uninstall slugify, delete a package
sharing project, dont include node-modules, just keep package.json and package-lock.json and “npm install” to reinstall required packages
nodemon –save–dev, nodemon helps to refresh server when saving
morgan, middleware
Section 3 – Backend Dev
Dynamic = backend rendered, API = get data from backend, rendered on frontend.

Section 4 – Node
Relies on V8 (written in JS,C++) to understand JS, libuv (C++) for async, i/o and various other processes.
Event-loop

Here we emit and listen(on) our own events:

Here we use built-in nodejs event emitter:

Streams, read and write at the same time.

Export Module
Section 5 – Async
Build a Promise
resolve and reject are actually functions
resolve puts data into then()
reject puts err into catch()

Consume a Promise
catch make use of the err, then make use of data
at each step, return a promise so that we can chain then & catch

other approach using async, await
write synchronous looking code with async effect
handle error with try { } catch { }
throw to mark the whole function as error, therefore escape
res_Pros will store promises, and 3 will be triggered and waited for at the same time with await Promise.all

Section 6 – Natours – API
Official reference: https://expressjs.com
Most basic requests in express
set up with app.listen
app.get returns data, status 200
app.post creates data
res.json, or res.end will end the request-response cycle.

Complete post request
newId created from the last ID
newTour created with assign function, pushed into all tours
status 201

pass params into request, access with req.params
? indicates optional param

app.patch update data, status 200

app.delete, status 204, return data: null

refactoring into functions

using .route, and chain requests of same route into 1

Middleware
do extra stuff between request and response
takes the form app.use( your middleware function, with 3 arguments req,res,next )
always call next() at the end

morgan middleware, console log request info

place holders for unbuilt routes

Using Router


Refactoring/Mounting into Route, Controller, Server, Express


add middleware by param on url,
val is avail, and should be used for param middleware only
no val for other extra middleware

Environment variable, can be acccessed with process.env (quite lag)
create config.env file and link to server.js file with dotenv.config({ path: ‘./config.env’ });
beware the loading process, env might need to load first so that app.js can use process.env.PORT

Troubles setting env var diriectly on 1 line as nodemon server.js or npm start, windows works differently with these command, nodemon always comes first

ESlint
https://eslint.org/
npm i eslint to check for possible bug
prettier
npm i prettier
create file .prettierrc, {“singleQuote”:true}
Section 7 – MongoDB
Download and install https://www.mongodb.com/download-center/community
Open cmd, run mongod.exe and mongo.exe, db -> test, set up completed (will need to create folder C:\data\db )
To start db in another path/folder, type env to start menu, edit environment variables. add path to mongo bin, run 2 files above in the desired folder

mongoDB docs on operators https://docs.mongodb.com/manual/reference/operator/query/
use natours-test, switch to or create a database
db.[collection].[function]
db.tours.insertOne( { name: “New Tour!!”, price: 100, rating 4.5} )
db.tours.insertMany( [{obj1}, {obj2}] )
show dbs
show collections
db.tours.find()
db.tours.find( {name: “Object name to find”} )
db.tours.find( {price: {$lte: 100} }), find document with price less than or equal to 100
db.tours.find( {price: {$lte: 100}, {rating: {$gte: 4.5}} } ), and 2 conditions
db.tours.find( { $or: [ {price: {$lte: 100}, {rating: {$gte: 4.5}} ] }, {name: 1} ), or 2 conditions and only get the name
db.tours.updateOne/Many(condition,set), use to change, or add new data, One applies for the first found object
db.tours.updateOne({name: “Any tour”}, {$set: {price:11111} })
db.tours.replaceOne/Many, replace all data
db.tours.deleteOne/Many(condition)
db.tours.deleteMany({}), delete all documents
Create MongoDB Atlas account
Create a new project, start a cluster, get some kind of key authentication
Link that cluster to Mongo Compass, with the authentication
Section 8 – mongoose
https://mongoosejs.com/
create Schema and Model

add data with new a instance of model and .save()

add data directly with .create()

getOne, Model.findbyId(), or .find(_id)
update, Model.FindbyIdandUpdate, new = true to return the new updated data, runValidators = true to revalidate the input with Model’s validators

Refactor into Model, which separates mongoose operations

const queryObj = { …req.query }; making hard copy of an object in JS
query string: localhost:3000/api/v1/tours?duration=5&difficulty=easy
can be accessed by express() with req.query
2 ways to make queries, object or chaining

it’s better to save the query first, and await later for the result. Build query first, execute later, because that query can be useful for other operations, where we actually await to get the final result.

more complicated query
localhost:3000/api/v1/tours?difficulty=easy&limit=10&duration[gte]=5
the parsed query string from req.query is close, but not identical to the required syntax of mongoose, i.e missing the $ sign, so we need some string manipulation to modify :
queryStr = queryStr.replace(/\b(gte|gt|lte|lt)\b/g, match => `$${match}`);
mongoose query documentation
query.sort(‘a -b’), mongoose sort by a (asc) and b (desc with the -). But the url has no space, hence seperated by comma url.com?sort=a,-b
query.select(‘a b’), may add select: false to schema to never select a field
.limit(l), .skip(s), skip first s docs, show next l docs, url.com?page=p&limit=l
Aliasing, reducing from
localhost:3000/api/v1/tours?fields=price,name,duration,ratingsAverage&sort=-price,-duration&limit=5 to
localhost:3000/api/v1/tours/top-5-cheap
add middleware to modify query


Refactor into a Class API
Aggregation pipeline, very similar to data piping in R or Python
Stages: https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

model virtuals schema, fields that are calculated based on other fields, not stored on database, but available when query.

4 Mongoose Middlewares: Document, Query, Aggregation, Model
this objects in the function either point to the current doc, current query or the current aggregation object


to exclude all secret tours out of aggregation, instead of going back and change all the pipelines, we can simply make a middleware for the adjustment.

Data validation
String: maxlength,minlength,enum(possible categorical values), trim
Number: min,max
Date: min,max
for post and patch/update,
for patch/update there’s an option to re runValidators:true or just let update to anything by setting to false.
Custom Validators with customer properties:

validators library, npm i validator
https://github.com/validatorjs/validator.js?files=1


Section 9 – Err handling
Install node debug as dev dependency, npm i ndb –save–dev
ndb server.js
* applies to all other route to give 404 response

refactor for centralized err handling
1. app.all router will just pass an error object to next
2. err object will be handle by a centralize place later

Make a separate class for err handling
build custom status & statusCode
anything passed into next() is assume as an error, and the middleware stops there!


Need to return next() here, not just next() because it will continue to respond with res.status below.

Handle not found Error in getTour, i.e correct format ID request but not found
Handle bad request with invalid ID to getTour
Handle duplicate name error


Handle mongoDB login error -> unhandledRejection
process.on here is a listener
Handle any other err in code -> uncaughtException. A fun test is to put error code in app.js, then only when we start to interact with server, the error will be run.
Comments
Post a Comment