NodeJS - Express, Mongo, Sequelize, Sequelize-CLI, Mongoose, GraphQL, Websockets, Socket.io, REST APIs, ReactJS Social Network, Winston, Morgan, Helmet, Compression, Validators, SSL/TLS, Micro Services Architecture & lot more. My personal notes and apps.
Aditya Hajare (Linkedin).
WIP (Work In Progress)!
- Weather App: https://aditya-hajare-weather-app.herokuapp.com
- Tasks Manager App: https://aditya-hajare-nodejs-task-app.herokuapp.com
- Socket.io Chat App: https://aditya-hajare-socket-chat-app.herokuapp.com
Open-sourced software licensed under the MIT license.
- Options Request
- Debugging Using Node Debugger
- Call Stack
- Event Loop
- Deploying Weather App On Heroku
- JEST - Things To Know
- WebSockets Protocol
- Mongoose - Things To Know
- Cookies
- Sessions
- Storing Sessions In MongoDB
- Allow CORS For REST APIs
- GraphQL
- GraphQL Query Variables
- Browser sends a
OPTIONSrequest before it sendsPOST, PATCH, PUT, DELETEetc.. requests. - You may typically get
405 (Method Not Allowed)error. Express GraphQLautomatically declines anything which is not aPOSTorGETrequest. So theOPTIONSrequest is denied.- To fix this, install
corsbynpm i cors --saveand use it as below:const cors = require('cors'); const app = express(); app.options('*', cors()); app.use(cors());
- Add
debuggerkeyword wherever you want to stop your program execution and begin debugging. For e.g.://app.js console.log('Hello World'); debugger; // This is where program execution will stop and you can start debugging. console.log('Hello World 1'); - Run
app.jsabove withinspectcommand as below:// In terminal node inspect app.js - Open
Google Chrome Browserand enter following URL:chrome://inspect/#devices - You should see your current Node app under
Remote Target. Click oninspectlink. - On left hand side, click on
Add folder to workspace.
Call Stackis a simple data structure provided by theV8 JavaScript Engine.- It's job is to track the execution of our program and it does that by keeping track of all of the functions that are currently running.
- The
Call Stackdata structure usesFILO (First In Last Out)to track the execution of our program.
Event Looplooks at 2 things:- It looks at the
Call Stack. - And it looks at the
Callback Queue.
- It looks at the
- If the
Call Stackis empty, it's going the run the items fromCallback Queue. - The
Event Loopactually have to wait untilCall Stackis empty before it could run items fromCallback Queue. - None of our
Asynchronous Functionsare going to run unlessmain() Functionis done executing. - Node uses other threads (
C++) behind the scene forNode APIs.
- Go to local Git repository root directory or project root directory.
- Execute following command:
heroku create [SUB_DOMAIN] // For e.g. heroku create aditya-hajare-weather-app - NOTE:
aditya-hajare-weather-appis the sub-domain and it must be unique acrossHeroku. - From your project root, execute following command:
heroku git:remote -a [APP_NAME] // For e.g. heroku git:remote -a aditya-hajare-weather-app - Execute
git remoteto list remote branches. You should see something like below:heroku origin - NOTE:
herokuis listed underremotes. - To Deploy:
- To deploy master branch to Heroku:
git push heroku master - To deploy contents of specific directory to Heroku root:
git subtree push --prefix [DIRECTORY_NAME] heroku master // For e.g. git subtree push --prefix 10-Weather-App-Express heroku master
- To deploy master branch to Heroku:
- After deployment, you can visit your app in browser. For e.g.
// Weather App on Heroku: https://aditya-hajare-weather-app.herokuapp.com/ - Heroku Environment Variables:
- To set environment variable in Heroku environment:
heroku config:set KEY=VALUE - To unset/remove environment variable in Heroku environment:
heroku config:unset KEY
- To set environment variable in Heroku environment:
.toBe()uses===operator to compare values. i.e.1 === 1: True{} === {}: False. That is because when 2 objects are compared with===they are not equal as they are stored in different memory locations.
- To compare objects in JEST, use
.toEqual().
WebSocketis a separate protocol fromHTTP.WebSocketsallow forFull Duplex Communication.Full Duplex Communicationis just a fancy term forBi-Directional Communication.- With
WebSocketswe have aPersistent Connectionbetween client and server. Socket.ioneeds to be called with a rawHTTP Server.- Event emitters:
socket.emit('EVENT_NAME', { dataObject }): Only to self/specific client.socket.broadcast.emit('EVENT_NAME', { dataObject }): All other clients except self.io.emit('EVENT_NAME', { dataObject }): All clients including self.
- Event emitters in
Rooms:io.to(room).emit('EVENT_NAME', { dataObject }): Emits an events to everybody in a specific room.socket.broadcast.to(room).emit('EVENT_NAME', { dataObject }): Emits an events to everybody in a specific room except self/specific client.
- While defining methods on
Schema, avoidArrow Functions. Instead opt out forfunction().- Reason:
thisis not available inArrow Functions. - Refer to following examples:
17-Shop-App-Mongoose/models/user.js 11-Tasks-Manager-App/src/models/user.js 11-Tasks-Manager-App/src/models/task.js - For e.g.
const mongoose = require('mongoose'); const userSchema = mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true } }); userSchema.methods.helloWorld = function() { // Not using arrow function here! // Code }; module.exports = mongoose.model('User', userSchema);
- Reason:
- Cookies which are not having
expiryandmax-ageset, will get destroyed when browser is closed. - To set a cookie:
exports.postLogin = async (req, res, next) => { res.setHeader('Set-Cookie', 'isAuthenticated=true; HttpOnly'); res.send(req.body); } - To fetch value of
isAuthenticatedcookie:const value = req.get('Cookie') .split(';')[1] .trim() .split('=')[1];
- To use sessions in
Express, install following plugin:npm i express-session --save - Steps to initialize and use session:
- Initilize session in middleware in
app.js:const session = require('session'); const app = express(); app.use(session({ secret: 'some secret string', resave: false, saveUninitialized: false })); - Session will be available on
req.session. - To set a value in session:
req.session.isLoggedIn = true; - To fetch a value from session:
const loggedIn = req.session.isLoggedIn;
- Initilize session in middleware in
- Install following package:
npm i connect-mongodb-session --save - Setup
MongoDB Store:const session = require('session'); const connectMongoDBSession = require('connect-mongodb-session'); const MongoDBStore = connectMongoDBSession(session); const store = new MongoDBStore(); app.use(session({ secret: 'some secret string', resave: false, saveUninitialized: false, store }));
- Method #1:
- Using express
corsmiddleware package:- Install
corsnpm package:npm i cors --save - Use it in
app.js:const express = require('express'); const cors = require('cors'); // CORS const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); app.use(cors()); // CORS app.listen(8080);
- Install
- Using express
- Method #2:
- Manually setting headers (NOTE: May not work in most cases):
const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); app.use((req, res, next) => { // CORS Middleware res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); }) app.listen(8080);
- Manually setting headers (NOTE: May not work in most cases):
- Uses
Typed Query Language. - Single
POSTrequest endpoint. For e.g.POST /graphql POST Request BodycontainsQuery Expression (to define the Data that should be returned).- Operation Types:
Query: To retrieve data.Mutation: To manipulate data.Subscription: To set up realtime connection viaWebsockets.
- Example #1
- Query without using variables (Non-Recommended Way):
const graphqlQuery = { query: ` { posts(page: ${page}) { posts { id title content imageUrl creator { name email } createdAt updatedAt } totalPosts } } ` } - Query using explicit variables (Recommended Way):
const graphqlQuery = { query: ` query FetchPosts($page: Int) { posts(page: $page) { posts { id title content imageUrl creator { name email } createdAt updatedAt } totalPosts } } `, variables: { page } };
- Query without using variables (Non-Recommended Way):
- Example #2
- Query without using variables (Non-Recommended Way):
const graphqlQuery = { query: ` mutation { updateStatus(status: "${this.state.status}") { status } } ` }; - Query using explicit variables (Recommended Way):
const graphqlQuery = { query: ` mutation UpdateUserStatus ($userStatus: String) { updateStatus(status: $userStatus) { status } } `, variables: { userStatus: this.state.status } };
- Query without using variables (Non-Recommended Way):