JS beyond a Browser
Intro
NodeJS creates conditions to use JavaScript outside of a browser.Simply put, it is an open-source runtime system for making server to run JS applications. In the project, I build and deploy the REST API application to Heroku which is the cloud platform in the PaaS model.
REST API:
- Web service APIs that adhere to the REST architectural constraints are called RESTful APIs.
- RESTful web service API allow requesting system to access or manipulate textual representation of web's resources.
- Requesting system has a set of uniform and predefined by API stateless operations.
- When we say that operation is stateless, it means next operation doesn't know about previous ones. In other words, operations on Web resources are independent.
- Requesting system can call available operations using HTTP requests: GET, HEAD, POST, PUT, PATCH, DELETE, CONNECT, OPTIONS and TRACE.
- RESTful Web service, makes web rosurces available under a specific Uniform Resource Identifier (URI) which is a string that provides a unique address where a resource can be found.
- Sending request to a resource's URI results with response in format of HTML, XML or JSON.
- In practice, when system or user is requesting, it sends chosen HTTP request under a specifed URI with defined parameters in form of JSON (when for example updating a resource).
ReactJS:
- It is a JavaScript library for building an interactive User Interface for a web applications.
- It builds User Interface with single reposibility componenets that creates final look and functionality.
- However, it still needs to work on an engine that loads the app into a broswser.
NodeJS:
- It works like the web-server that accepts API calls from a client/user.
- It loads single index.html of the React application with all the dependncies (CSS, JS) into a browser.
- Depending on the API call and path passed from an user, the appropriate React components fills the index.html what user sees on the screen.
- These components comes with textual representation of API resources that represents data in a database.
- Things like what resources (endpoint = path) are available and in which way (reqest type = type of API call) - they are handled by nodeJS server.
MongoDB Atlas:
- The global cloud database service for modern applications.
- Strucutre of MongoDB Atlas is JOSN format alike.
- Connection to cloud database comes directly from nodeJS.
Heroku:
- We can deploy our application into cloud platform.
- Heroku offers PaaS solutions for many programming languages.
Workflow:
- User sends API call to a specific route (web path) from react web-application.
- NodeJs web-server accepts request and loads index.html of the React application to the screen.
- ReactJs reads passed route and based on that loads appropriate components into index.html.
- NodeJs, depending on the route and API call, sends the database resources that feeds React's front-end elements.
- User sees a complete application.
Features
App includes following features:
Demo
Setting up nodejs server:
- We can run NodeJS server by using Express:
const express = require('express')
const port = 3080
const app = express()
...
app.listen(port)
HTML templates:
- Html templates for being rendered to a browser are keptin in directory: './views'
- Html templates requires '.hbs' extension.
- We need to install hbs with npm.
- We let html template to be rendered for a specific endpoint, here '/home':
app.set('view engine', 'hbs')
app.get('/home', (req, res) => {
   res.render('index')
})
HTTP request:
- Which request is going to be handled by an enpoint is specified as app method:
app.get('/home', (req, rest) => ... )
- Besides get, there are also post, delete, patch (like update).
Connecting with MongoDB Atlas database:
- At first we need to import mongoose:
const mongoose = require('mongoose')
- Then we can set up a connection:
mongoose.set('useUnifiedTopology', true)
mongoose.set('useNewUrlParser', true)
mongoose.connect(process.env.DB_CONNECTION, function(err, db) {
  console.log('Connected to db.')
})
React state:
- State is assigned to a given class component.
- We can update state by executing some class functions or on some evens like user filling a form.
- Here is the example of updating state on every change on user's form:
- it updated itself with each character provided in each field,
- thanks to that we can keep the input data in the state on an ongoing basis without even submitting by user,
- code:
onChangeForm = (e) => {
    let user = this.state.user
    if (e.target.name === 'firstname') {
        user.firstName = e.target.value;
    } else if (e.target.name === 'lastname') {
        user.lastName = e.target.value;
    }
    this.setState({user})
}
- the form's fields needs to be have names provided: firstname and lastname respectively.
Deploying on Heroku:
- It requires Heroku CLI installation in order to upload the application.
- It requires also git installation to commit the application to Heroku repository.
- Here goes deployment procedure:
in code:
const port = process.env.PORT || 30000
in package.json:
"start": "node main.js"
terminal:
cd project
heroku login
git init
heroku git:remote -a arturskrzeta
git config user.email ...
git config user.name ...
every time change in the project:
git add .
git commit -m "initial commit"
pushing changes to heroku repository:
git push heroku master
- App availabe at:
arturskrzeta.herokuapp.com
- Logs available with:
heroku logs --tail
- Push successful:
Postman
- I use Postman for resource's URIs testing.
Node and React integration:
- Making NodeJS server listening on the port 3080.
- ReactJS runs on port 3000.
- We need to ensure interaction between these two setting up proxy in React's package.json:
"proxy": "http://localhost:3080"
- By doing so, we can be sure that all API calls will be directed from Reat Web-app to http://localhost:3080 where the nodeJS API is listening.
- In the project, React app has the sevice file which contains async functions that use fetch API to make the API calls to the node API.
export async function createUser(data) {
  const response = await fetch('/api/user', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({user: data})
  })
  return await response.json();
}
- POST workflow:
1. User filling up the form updates state in React web-app.
2. React web-app imports service function and passes state data as argument.
3. Service function makes API call to node API.
4. Service funcion's API call is actually the POST request with request's body which is passed React's state.
5. Node API accepts request and saves passed data to database and returns response in JSON.
6. React updates its state accordingly and renders the appropriate component to display graphical element along with updated data.
- Let's go with the example of sending POST request to http://0.0.0.0:3080/users endpoint:
1. Request goes to main.js which is a core file configuration of nodejs server.
2. main.js uses line of code:
app.use('/users', require('./routes/users'))
for rerouting enpoint '/users' into './routes/users'.
3. In the users.js, the router.post accepts the request and contains the logic on how to handle it.
4. For example the router creates instance user of User model, populates its attributes with received data and saves the instance do the database.
- GET workflow:
1. User sends GET request from React web-app.
2. React web-app imports service function that makes API call to node API.
3. Service function's API call is actually the GET request.
4. Node API accepts request and fetch a data from the database.
5. Node API sends the response in JSON format to React web-app:
  {firstName: "user_fn", lastName: "user_ln", email: "usera@gmail.com"}
6. React web-app receives response and updates its state with it.
7. React web-app rerenders component to display the fetched data.
- Let's take GET request to http://0.0.0.0:3080/ endpoint:
1. Request goes to main.js which is a core file configuration of nodejs server.
2. main.js uses line of code:
app.use('/', require('./routes/index'))
for rerouting endpoint '/' into './routes/index'.
3. In the index.js, the router.get accepts the request and contains the logic on how to handle it.
4. For example that router can render index.html in response that shouws up on user's screen.
Microservices architecture
- I try my best to apply microservices approach which structures an application as a collection of services that are independent and has single responsibility.
- With that approach we are sure a web-app is safe. When service fails, it doesn't affect other sevices and web-app overall.
- It fulfils continoues delivery approach as a samll part of the application requires rebuilding and redeploying one or few services.
- Perfect for network communication processes that use technology independet protocols like HTTP.
- In the project I use services like creating an connection, fetching all connections in one table, deleting a selected connection.
Application
Setup
API installation:
- Npm initialization:
cd ./api
npm init
- Npm extension installation:
npm install express
npm install hbs
npm install nodemon
npm install mongodb
npm install dotenv
npm install body-parser
npm install bootstrap
- Modifying package.json:
"scripts": {
  "start": "node server.bundle.js",
  "build": "webpack",
  "dev": "nodemon ./main.js localhost 3080"
}
- Running nodeJS server:
npm run dev
Application installation:
- Npx installation:
npm install -g npx
- ReacJS installation:
cd ./application
npx create-react-app application
- Setting up scripts in package.json:
"scripts": {
   "start": "node server.bundle.js",
   "build": "webpack",
   "dev": "nodemon ./main.js localhost 3080"
},
- Setting up proxy in package.josn:
"proxy": "http://localhost:3080",
- Running ReactJS application:
npm start