class-1: NODE
-
CommonJS and Modules && Paint with colors the terminal without dependencies
- How to import and export commonjs files and modules
- How to paint with color, background color, and text changes on terminal
-
OS info
- OS Info from
node:os
- It can be access to: platform, release, architecture, cpu, free memory, total memory and more
- OS Info from
-
FS stat: isFile, isDirectory, isSize
- Can now if a something is a file, is directory, the size with
node:fs
- Can now if a something is a file, is directory, the size with
-
Read a file: sync, callback, promisify
- Can read a file sync, with callbacks and using promisify
- Caveat 🟨: only tested with
.txt
files
-
Read a file: IIFE, promises-then, async await (sequential), async await (parallel)
- Can read a file sync, with IIFE, promises-then, async await (sequential), async await (parallel)
- Caveat 🟨: only tested with
.txt
files
-
Path, with
node:path
is possible to:- Know the path separator for your actual OS
- Get the absolute ir relative path
- Know if a route is relative or absolute
- Know the file name from a given route
- Know the file extention from a file
- Know the file plus extension from a given route
-
LS: promises, promises-then
- This is a app that list the files from this folder in a promisify way and in a Sync way
-
Process: how to take arguments by terminal
- The
process.argv
give you access to argumentos of entry: with this you can configure things in the command line, if you made an API and you want put configurations there passing arguments to it. This is an array - With
process.on("exit", callback)
can do things when the process end, of the process, specific errors, and so son - The
process.cwd()
is the Current work directory (cwd): says where which folder we are running the process, not where is the file but from which folder the command was executed to run the file - The problem with
node
is it can access to.env
variables leading acccess to too many power like deleting files, for example
- The
-
LS advance: thenable, async await, arguments, prompt
- More advance
ls
with a thenable, async await, arguments and prompts on terminal
- More advance
-
Http server
- Creation of a http server only with
node
- Creation of a http server only with
-
Free port method
- Method to get a free port if the desired is used
class-2: HTTP && Express
-
HTTP Server
- HTTP is one of many protocols that are useful to transfer some type of data. In this case HTTP means HyperText Transfer Protocol (HTTP). This is the most used on internet to transfer data, specially web pages. Examples:
- A user have some device (a phone) and wants to reach some content. In order to reach it the user should make a request. The request have a:
- url (where are you making the request)
- headers (aditional information about the request like tokens, type of data we are especting to receive, we can send the cookies). Those are optional
- the method (the type fo request: GET —to request— or POST —to send— or others)
- and sometimes we send a body (data we want to send)
- The request reach a Server. The server will process it the request with everything sent from the user (it will go to a database, treath the data). That process will take some time (unknow time) and when this finish it will send a response to the user.
- The request and the response have different data and this is critical to understand how all of this work. Every part have to send different data
- The data that the response have is:
- statusCode (200, 404, 500, etc)
- body of the response: this are actually the data that you asked
- headers
- After receiving the data, the conextion should be closed unleass some header will say that it should keep open
- A user have some device (a phone) and wants to reach some content. In order to reach it the user should make a request. The request have a:
- Caveats 🟨:
- With the statusCode: in reality this is in the header but is important this to be alone because when the headers is writen first the statusCode is writen and after that the headers
- The HTTP protocol historically had so many security problems and therefore exist the HTTPS protocol. This can be used on localhost but is too complicated and it require a certification. Right now we are going to focus on the HTTP and the API. Another problem is having a service on HTTP on localhost that works correctly but when you deploy it you wrapp that in a service that use HTTPS, therefore interanally is HTTP but is wrapped in HTTPS so everything is encrypted and it doesn't have any problems
-
Status code:
- From 100 to 199: Informational
- From 200 to 299: Success
- From 300 to 399: Redirection
- From 400 to 499: Client error. The client tried: enter to a page that doesn't exist; send data in a wrong format; it doesn't have permission to access to something
- From 500 to 599: Server error
- Recommended source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
-
Typical statusCode:
- 200: OK. This is the default, it can be omitted if everything goes okay
- 301: Moved permanently. The resource of this direction was moved to
- 400: Bad request
- 404: Not found
- 500: Internal server error. This is a tricky one because you will not know exactly what happened
-
Buffer data on the file
class-2/1.http.js
:- The "data" second argument here is a Buffer. A Buffer is a global class in nodejs that is useful to work with binary data: a when a .txt file or an image is received by nodejs is readed they binary data and is stored, temporary, in some place of the physical memory to work with them.
-
Before the read of the data nodejs doesn't know what it is: an image, a text or other, is just a binary data. The nodejs know that is an image when reach the "else" where the header is set to "Content-Type: image/
extension
". Here the codification magic happen: the browser know is an image because the Content-Type setted. - The buffers are useful to work with files, images, criptography and anything that is not plain text or jsons. Those are critical when you want to work with data transmision because how to file are readed or to received through the network
- HTTP is one of many protocols that are useful to transfer some type of data. In this case HTTP means HyperText Transfer Protocol (HTTP). This is the most used on internet to transfer data, specially web pages. Examples:
-
Routing
- In commonJS you can import json data directly and use it
- Methods of routing:
- GET: To get data
- HEAD: Is exactly the same as get but without the responding of the body. Is usually used to know if the user have permission to access to some content
- POST: To create data
- PUT: To update data, this replace the content
- PATCH: To modifiy partially some data
- DELETE: To delete data
- OPTIONS: This is used to know which communication are available for the target resource. This is usually the problem we have on CORS on browser. The browser make a request to a server and this server send a response with the type of comunication allowed. The OPTION return the headers CORS
- Caveats 🟨:
- There's some discusión about the use of POST versus PATCH. Search it
- In this class the file api.http was used
-
Express
- When you use express it add some header call X-Powered-By with the value of "Express". This could lead to security problems because everyone can know te technology you are using and try to exploit vulnerabilities there. is recommended to disable this with «app.disable("x-powered-by")»
- One of the magic thing of express is the use of middleware. This can be used to extract cookies, validate if the user is logged, extract the data from json or any type of logic. Is something previous to to do before it arraive to the request. When it's done it call the «next()» method to continue. The middleware is executed between the request and the response
-
Middleware:
- You can decide to which request the middleware will affect. For example:
- app.use("/pokemon/*", fn) → All the requests that start with "/pokemon/*" will be affected
- app.use("/", fn) → Only the request on home will be affected
- app.use(fn) → All the routes will be affected. This is the usual behavior
- The middleware can be used also for specific methods: only for GET, only for POST
- Caveats 🟨:
- You shouldn't forget the final «next()» method because if you forget it will wait infinitely for the next request
- A middleware can be used at first, in between or at last. The concept of this is "be in the middle" but technically the «app.use()» can be used as a middleware anywhere. Is like a proxy, intercep the request to respond it later. A proxy and a middleware intercep a request but the final goal is different: the Proxy will have the responsibility of orchestration but the Middleware will do that and apply some logic or task into it. A Middleware could reject a request
- You can decide to which request the middleware will affect. For example:
- On Express the method
app.use(express.json())
ccan be used to make something a json. See the fileclass-2/3.express.js
on line33
to learn it - Express allow you to use the route first and the callback after
- In the post, everything is the same as nodejs
- The calls of
app.*
is dependendat on the order - The API
app.liste
is the same as nodejs
class-3: CORS + API Rest with Express
-
API REST
- REST mean: Representational State Transfer an Software Architecture (not a framework, not a library, not an idea, not a pattern)
- Was created to transfer data specially on web
- Was created on the 2000 year by Roy Fielding
-
Principals features on REST:
- Scalability
- Simplicity
- Visibility
- Portability
- Realiability
- Easy to modify
- All Software Architecture should achieve a goal with some principals that can sustain over time the best possible way and simplify the creation of that piece of software. This is the goal of every Software Architecture
-
Fundamentals on REST:
- Resources: everything here is a resource (a user, book, some publication, an image or a collection of this resources, a list of users, books, and so on). Every resource will be identified with an URL
- Methods: what kind of action you want to do with the resource. This could be GET, POST, PUT, PATCH, DELETE, HEAD, CONNECT and TRACE. The most common actions made here are the "CRUD" → Create (POST), Read (GET), Update (PUT or PATCH), Delete (DELETE)
- Representation: This is how the resource is represented: the most common representation is JSON but is not mandatory, this could be also XML, HTML, CSV, etc. The client decide which representation be the resource, having none restriction on the format. One client can ask for a JSON while other client can ask for a XML representation
- Stateless: every request to the server should contain all the neccesary data to understand that request. This mean the server should not be able to remember anything about the request. For example it cannot save how many calls have been made to the server, it have to make pagination or not, that data should be always on the URL of the request. Sometimes some data can be save to help the client but in that case the REST architecture will be break. Another case is when we have some database on the backend.
- Unified interfaz: this is difficul to break it but it means that the interfaz between client and server should be consistent for every interaction. The URLs should always do the same, should always be called the same
- Separation of concepts: components of client and server should be separated. This allow the server and the client evolve independently
- Caveat 🟨:
- Sometimes you can make some API that is not REST, another architecture exist (like SOAP or GraphQL). Some people think that an API that return a JSON is immediately a REST API but it is not always the case
- Resources: sometimes you can decide to identify the resources with a path on the URL or with some queries. It will depend on the specific use case you want to achieve
-
Express use path-to-regex
- Is possible to put regex in the URL but express use this library: path-to-regex, like this
app.get("/movies/:id", fn)
- Is possible to use
/movies/:id/:couldBeMore/*:andAsMuchAsYouWant
where the:id
,:couldBeMore
,:andAsMuchAsYouWant
and*
are part of the URL separated by an slash. Is your decition using it this way or making them query params - Everytime you can, use path-to-regex because make the regex by you can lead into problems
- To know more check the github repository of pillarjs or the express explanation in their documentationr>
- Is possible to put regex in the URL but express use this library: path-to-regex, like this
-
POST, PATCH, PUT and Schema (Zod)
- To Understand the POST: You have to work all the time in the same route, is not like you can put here `app.post("/create-movies", fn)`, this is because the Resource is defined by the URL and is the verb which decide what's going to be done there: GET, POST, other
- ID on Post:
crypto.randomUUID()
- With Zod: You can validate the data with the method "parse" or you can use "safeParse". With "safeParse" you will have a object result with data or errors. You can even use the safeParseAsync to avoid blocking the request return movieSchema.parse(objectToValidate)
- On the error of the validation of schema (Zod):
- You can pass here a 422 instead a 400:
- The 400 status code is because the client did something to lead on this error: sintaxis error, the data sent was not correct. The important thing here is: the client cannot do a new request without modifications
- Other approach is 422: the server understood the request, type of content but the sintaxis of the resource was not possible to created because some validation or instruction was not correct. The same as the previous: client will not be able to make another request is it not change something
- Final though, use anything you want
- Remember, a REST API don't save data by their own. For that, use a database
- Idempotence and differences between POST, PUT and PATCH:
- Idempotence: is the property of realize an action several times and even though achieve the same result as you would get with the first try. Pure functions are idempotent. This property talk about the inner state of something. Now the methods
- Purpose of POST: create a new element/resource on server
- On URL: `/movies`
- Idempotence: this is not idempotente because every time you call this method a new resource is created
- Purpose of PUT: update an existing element/resource on server o create it if it doesn't exist
- On URL: `/movies/:id` → `/movies/123-456-789`
- Idempotence: this is idempotente the bast majority of the time, but it could not be sometimes
- Purpose of PATCH: update partially an existing element/resource on server
- On URL: `/movies/:id` → `/movies/123-456-789`
- Idempotence: this is not idempotente ithe bast majority of the time, but it could be sometimes
- One question, is it danger to create the ID from outside? The answer: it could be but this will depend of the context of the application. For example, sometimes this ID can come from outside: the email of an user for example or other thing that will identify that person as unique in the analog world
-
CORS: Cross Origin Resource Sharing
- This only works on browsers not in servers. The CORS is a mechanism that restrict if a resource can be used on some origin. The browsers make the request to this resource. Here the browser on origin
http://localhost:8080/
akamywebsite.com
ask tohttp://localhost:3000
akaAPI.com
Is true that mywebsite.com who is not you (of course the browser ask in this situation, if would not, it would not ask) is able to get resources from API.com? - When this is not possible the way from the API to say no is with the lack of headers
- This problem can only be solved in the backend: on the API, on proxy, in the router or on anything that can add the required header. Who should add that header? For now that's not important
- The way to to solve this in express is adding this to the routes you want to enable
res.header("Access-Control-Allow-Origin", "http://localhost:8080")
. In this casehttp://localhost:8080
would be mywebsite.com - You can also replace the specific
http
site for this*
, to enable all the request for anyone - Here is very possible that you don't know would be the origin, it would be
3000
,8080
,4500
,1234
? So, the solution for this could be:- Detect the origin and decide what to do. For example, you can have a list of
ACCEPTED_ORIGINS
- Detect the origin and decide what to do. For example, you can have a list of
-
A caveat here 🟨: the
origin
header is not always sent by the browser. This is not send by the browser when the request is from the same origin. This mean, if I'm in thehttp:localhost:3000
and I make a request tohttp:localhost:3000
noorigin
header will sent - Exist simples and complex methods with CORS:
- Simples:
GET
,HEAD
andPOST
- Complex:
PUT
,PATCH
andDELETE
- This methods have something call
Preflight
, this mean that you need to add a call with the methodOPTIONS
in order to make them acceptable
- This methods have something call
- Simples:
-
At the end the problem with
CORS
is a problem of headers. You should be able to useres.header("Access-Control-Allow-Origin", origin)
andres.header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
to solve it in the correct place: in the middleware and/or where the request is made - Is it possible to solve this using express or you can use a third party library call
cors
. Check theapp.js
file to check how to use it. One caveat 🟨 with that solution: it will solve adding an*
to everything. In order to make that library behave as the native approach you have to pass it some options
- This only works on browsers not in servers. The CORS is a mechanism that restrict if a resource can be used on some origin. The browsers make the request to this resource. Here the browser on origin
class-4: MVC and Deploying of API
-
Environmental variables
- This should be always on
UPPERCASE
- On express it can be used like this to deploy it on some service:
const PORT = process.env.PORT ?? 3000
app.listen(PORT, () => { console.log(`Server listening on port http://localhost:${PORT}`)})
- This should be always on
-
Configuration on hosting
- Normally the host ask you for a
start
script on thepackage.json
to run the file or maybe it will ask on the configuration
- Normally the host ask you for a
-
ESModules
- In order to use the ESModules instead the commonJS approach, you can go into your package.json and add this
"type": "module"
. With that you will be able to use the ESModules without change the extension of the files. But at the same time, you will not be able to use the commonJS approach without change the extension of the file - When you import some module is a good practice put the extention, like this
import { QUERY_KEYS, moviesQueryParams } from "./utils/moviesQueryParams.js"
. As developer we are bas used to not put the extension at the end, because we are lazy, because TypeScript, because builders - On ESModules import json is not allow directly
import allMoviesJSON from "./data/movies.json"
you can do it with different approaches:import allMoviesJSON from "./data/movies.json" assert { type: "json" }
→ This is not recommended because theassert
will stop work at some pointimport allMoviesJSON from "./data/movies.json" with { type: "json" }
→ Change theassert
forwith
-
import fs from "node:fs"
const allMoviesJSON = JSON.parse(fs.readFileSync("./data/movies.json", "utf-8"))
-
Recommended (until the import of JSON will be native on ESModules): create a require (this is more performante)
import { createRequire } from "node:module"
const require = createRequire(import.meta.url)
const allMoviesJSON = require("./data/movies.json")
- In order to use the ESModules instead the commonJS approach, you can go into your package.json and add this
-
MVC: Model, View, Controller
- Exist some debate if the MVC is a
Design Pattern
or aArchitecture Patterns
. It seems more like an architecture. Nonetheless, it doesn't explain everything because it doesn't tell you how to implement theView
- This is highly used on web and mobile applications but other frameworks also work like this, like
ruby on rails
,Django
,ASP.net
and others - This architecture forces you to separate the application in three main component that work togheter, the Mode, the View and the Controller
- Exist several iteration of this architecture. But the one we going to see here is the most classic one
Model:
- This is the logic of the business, the data structure, inner rules of the business
- This is in charge of access the database, update the data, check if the integrity of the data are correct (for example, if you try to create and ID, that ID shouldn't exist)
View:
- This is the most important part for the user: with this the user will interact because the user cannot interact with the Model neither the Controller
Controller:
- This is an intermediary between the Model and the View, this respond to the entries of the user every time they make on. This part of the application is responsable for know what to do with the model. Is like an Orchestrator
-
This three parts should work togheter. First the controller will ask for data to the
Model
, the model will return the data to theController
and after that it will init theView
. After that the user throught theView
will interact wanting something happen. With that interact of the user theController
will act asking for the correct data to theModel
, generally speaking having theCRUD
approach here with them -
Remember here, from the
View
is not possible to interact directly with theModel
. But is possible indirectly because the user, at the end, make some request to theModel
through theController
-
The advantage of this is the separation of the responsabilities on the application, specially the Logic of the Business (
Model
), because this is the most important thing on the application when it have to connect to a database. This will help to scalability and test, to name some - Examples:
View
:React
Vue
Controller
:Express
DJango
Model
:mySQL
mongoDB
- Local
- The goal is have black boxes that interact with each other. Each one should know how to interact with the other but it doesn't whould know how them interanally make their things. This is the key of architecture and clean code: separation of by layers, separation of concepts
-
In the code is not neccesary that the
Model
and theControll
share the same names for the methods. Even sometimes you will need to call more than oneModel
from theController
- Validations:
- This happend along all the aplication:
Model
,View
,Controller
but is made in different ways depending on the category Controller
: usually here the validation is of format and coherence of the data received, to be possible to be procesed before send it to theModel
. When it comes from the input from the user, is a good thing to validate the data before to send it to theModel
. With this validation you allow the data is correct to be used or to avoid attacksModel
: usually the validation here are for the business rules, data coherence, data persistant in the database and others like check the ID- The
View
is the most useless for the business logic but is the most important in terms of user experience - Is debatable if the
Model
can have some method that say which field allow and with wich type, like a integer, a string and so son. That method can be exported into theController
to make the validation there. Here the validation will stay apply in theModel
but it will be used, also, by theController
- With this said: validation on
Model
andController
are mandatory, validations onView
are optional (very interesting)
- This happend along all the aplication:
- Exist some debate if the MVC is a
-
Difference between
Design Pattern
andArchitecture Pattern
- The
Design Pattern
: is an easy, repeteable, to solve something specific in a part of the code. For example:- Pattern Observer
- Pattern Factory
- Pattern Modules
- The
Architecture Pattern
has to do with all your application: how to implement everything - The architecture on software development make sense when you work on business with products or services. In order to be a Software Engineering, you need to create products that scale, be maintainable and work
- The
class-5: Creation of a database with mySQL and evoiding hackers (good practices)
- A database is a collection of data interrelated and saved without unnecessary redundancy
- All database should allow insertion, modification and delete of data
- There's two type fo data in a database:
- Date from users: created by the user
- Data of the system: data that the database use for their management. For example: which user have access to the database
-
The characteristics of a database:
- Versatile: depending of the user and application, it should behave acordly
- Performance: should have the enough speed for every client that make request to the database
- Low redundancy: should be the lowest possible
- High access capacity to gain the most possible time on requests
- High index of integrity: if any amount of user try to use the database, this should not fail for create new data, have redundancy or for slow updating
- Very high security and privacy. This taking in mind not only the software but also the hardware: fire, stealing, and so on
- Should receive periodic updates to avoid obsolescence
-
User should not know how the data is organized and saved. Becuase of this the data should be presented to the user in a easy way to be interpreted y modified. With this: exist three principals levels on for the user interact with the database:
- Intern level: closest level for the physical storage. It allow to write like is in the computer. Here you have the configuration files: files that have the data, direction of the files and organization
- Conceptual level: The data that will be used is presented without having in mind the Intern Level.
- Extern level: the closest to the user. Here the data that the user want is writen (totally or partially)
- The data within a database are naturally related, for example: a product belong a category and is associated with multiple tags. The term for this is
Relational Database
- A
Relational Database
is like a spreadsheet: atable
is a page, that containcolumns
androws
. Atable
can relate to anothertable
using various type of relationships likeone-to-one
andone-to-many
- What is
SQL
- The acronmyn
SQL
stands for Structured Query Language. This is the standarized language to access the database SQL
is composed of three parts:- Data Definition Language (
DDL
): includes statements for defining the database and its objects such as tables, views, triggers, stored procedures, etc - Data Manipulation Language (
DML
): contains statements for updating and querying data - Data Control Language (
DCL
): allows you to grant permissions to users to access specific data in the database
- Data Definition Language (
- The acronmyn
- Important
SQL
commands:start transaction;
: this is for make changes without commit it. With this you can make changes safely without worring to mess it up. In this state you can use therollback
to revert the changes. And when you be happy with your changes, you can use thecommit;
in order to apply all the changes
- What is
MySQL
- Is a robust database management system designed for managing relational databases. It is open-source software supported by
Oracle
, meaning that you can useMySQL
without any cost. Additionally, you will have the flexibility to modify its source code to tailor it to your specific requirements - When compared to other database software like
Oracle Database
orMicrosoft SQL Server
,MySQL
is relatively easy to master MySQL
is versatile and can run on various platforms, includingUNIX
,Linux
, andWindows
MySQL
is renowned for its reliability, scalability, and speed
- Is a robust database management system designed for managing relational databases. It is open-source software supported by
- In order to run some
sql
scripts you can:- Run a pluggin on vscode: MySQL by Weijan Chen, and this is the website database-client.com
- Or you can run by the
mySQL shell
following the nex steps:- Reach with the terminal the desired path or know the path of your file
-
Once you get the path run this on the terminal to open the
mySQL Command Line Client
:mysqlsh
-
You should explicty change use the
sql
shell with\sql
-
Now be sure that you are connected to the actual server running
\c [user]@[host_name]
: example\c root@localhost
. Maybe the terminal will ask you for a password -
Run the command
\. [name_of_script].sql
and done -
IMPORTANT: ⚡ Running the
sql
scripts this way will allow you to use theSOURCE
command, that comes from themySQL Command Line Client
which will help you to upload and run other scripts files in a more efficient way
- Dependency Inyection
- This is a
Design Pattern
to improve code efficiency eficciency, modularity, control, reusability and make the code testable. Also, the code is uncouple by design - The basic idea is: a
object
,class
orfunction
can receive their dependencies from outisde and the inner behavior change depending on how this information is provided
- This is a
class-6: Chat in real time with node, socke.tio, sql, html & css
- Available protocols
HTTP
: this is the more used on internetFTP
DNS
WebSockets
: usually real time chats use this protocol- And many more...
- What about
Transmission Control Protocol (TCP)
? This is for reliable delivery data packets
- Difference between
HTTP
andWebSockets
- Stateless: this allow the resource be 'cacheable', this mean if you want something that is always the same, the request should return all the time the same resource, like some text or image. Usually this is the case
- Use cases: html, js, images, rest API (CRUD), unidirectional, cheap process with high latency
- Is not Event Driven
HTTP
- Stateful: is not 'cacheable', is doesn't make sense some resource of a chat have this property
- Use cases: realtime, low latency data (high frequency communication), bidirectional information
- Is based on Events
WebSockets
- Making an real time chat:
- With
HTTP
: the user make a request to the server and the server provide a response. Further responses will require more requests. This is basically how internet works. To achive a real time (chat) you should use something call "polling", this mean, everyx
amount of time you will ask to the server if you have new data to serve. This is not real time. The problem with this approach is every request contain so much information, not only what we want plus the latency.- Other way to make it
HTTP Server Events
: this is very interesting but remain unidirectional
- Other way to make it
- With
WebSockets
: the user make an "Initial HTTP handshake", you tell to server "I want to initiate the data transfer, I'm using WebSockets" (is always the user who made the first conextion and is the server who decide to accept or not the conextion with WebSockets). After the first petition the conextion will persist withWebSockets
, this mean the user can send data to the server at any time but also, the server can send data to the user at any time. The conextion can be closed by the user of by the server. The magic of a "real-time-something" happen when the conextion is live. - Both,
HTTP
andWebSockets
usesTCP
- More advances concepts would be: multi, full, half duplex:
- Full: Allows data to be transmitted in both directions simultaneously over a single connection. Example:
WebSockets
- Half: Data can be transmitted in both directions, but not simultaneously. Typically, one direction is active while the other is passive. Example:
HTTP
andHTTP/2
- Multi: The ability to transmit multiple streams of data over a single connection concurrently. Example:
HTTP/2
- Full: Allows data to be transmitted in both directions simultaneously over a single connection. Example:
class-7: User authentication, session, cookies, JWT with Nodejs
- It's recommended to use third party libraries to manage all the authentication and authorization, but it's good to know the fundamentals
- Is recommended to avoid the use of
localStorage
at all cost, because: [Answer Pending]. Between all options,cookies
are the better thanlocalStorage
- You can use the desktop program Yaak to make simple requests to the server, is an alternative to postman
- Is it possible to use a
config.js
file to import and export all the things you need and have a more clean javascript file - In
Nodejs
version20.12.0
you can use this approach to load your.env
file://.env PORT = 8888 //config.js import { loadEnvFile } from "node:process" loadEnvFile() export const { PORT = 3000, OTHER_VARIABLES = "DEFAULT_IF_NOT_FOUND" } = process.env //.index.js import { PORT } from "./config.js"
- To work with a local databse, you can use the library
db-local
- To hash the password of users, yous can use the library
bcrypt
. Here is possible to usebcrypt.hashSync(password, SALT_ROUNDS)
and you have to be aware, the codification is expensive because cryptography is expensive (to much calculation, this mean, use the time of the computer). How to improve this you can use it with promises, like thisawait bcrypt.hash(password, SALT_ROUNDS)
- When you return the data from the server to the client with the
login
endpoint you have to manage apublic user
that's going to be exposed in the client and aprivate user
who is going to be used on the database. For thistypescript
is really useful - When the data is returned to the client, in the
source code
the data can be returned explitir or implicit, this would be the approach: Remove data you don't want on a objectconst { password: _, ...publicUser } = user
or you can return only the data you wantreturn { user: user.username }
- The important thing here is to make the hash, the validations on the server and also use
https
. You think "the client should hash before to send the data to the server" and this doesn't make sense because the server should make, again, the validation and the hash. Everything that is in the client is exposed to people and people can see what's the strategy you are using to save te data on the server. Therefore, the most important thing is the use ofhttps
- In the Frontend is not a big deal to cover the password because, if someone have access to the frontend, you are very fucked up. A different thing is that your request is intercepted, to avoid this interception you have to use some encrypted protocols (
https
, put the attention on the finals
at the end ofhttp
) - One way to unhash some already hashed password is with brute force or with gigantic dictionaries, when someone already know a password they also known which is the hash. For example, the password 012345 could be, for some encrypted method, this: $2b$10$S9POdgd2JHftZPX8xqq/M.WS7JnmzIlkORGq4BQkX/.NcVniP7Jii. And you can generate those usual and knowed password to hashed and compare it. This job is already done with huge dictionaries out there. You can try a old hash generator in MD5 and there you can see some password will generate always the same hash. Therefore, any hash method that use MD5 should be avoided. In the case of use of the class-7: JWT the encrypted library
bcrypt
is used, with this the data is unintelligible and irreversible to hackers even if they know the hashing algorithm. In other words, is imposible to get the plain text hashed, like a password - The
bscrypt
library is recommended for hashing password, unlikeMD5
,SHA1
,SHA2
, andSHA3
because this others are vulnerable when it comes to password security, but it can hash large amounts of data quickly - While is true the use of
bscrypt
is good for hashing password this doesn't remove all the possible vulnerabilities, because of this users should use longer passwords thans shorter complex one - If the
endpoint
needs some sort of state, this is, it needs to beidempotent
you should be use some database, likeredis
-
JSON Web Tokens (JWT)
-
The technology
JWT
can be use not only for the session of the user. This can be used to securely communicate and exchange data between two parties without the need for state. The token can then store that data. This allow to encode, decode and verify that the person or system is who they say they are -
Parts of
JWT
are:- Header: contains the type of token and the algorithm.
- Payload: data completely encoded
- Signature, verify signature or footer: this part allow you to decode the token. Also, here you have to choose a "secret-word". This word should be come from a environmental variable. This is very very important. If the "secret-word" gets exposed everything is exposed
- The idea is not to send all the data of the user in the token because the longer the payload, the longer the token
- In this class we are going to use the
JWT
to authentication without a state, a session on database. It allows you to have all the important information in the same token: when the token expire, which user is with the session initiated. This is very highly scalable, the database needed for this don't being huge. It have inter operativity (work in different languages, different platforms, different devices), is a open standard, works in any place, allow you to have security - In the a real world application the
JWT
should not be used in alocalStorage
,sessionStorage
or any related thing. TheJWT
should be in acookie
, why? Becausecookies
:- Are a little bit more secure
- Have less vulnerable to cross-site scripting attacks then
localStorage
orsessionStorage
. To be fear, the plugins of the browsers can have access to yourcookies
and re write it. So, bear that in mind. So, is not 100% secure but is a one more layer of defense - Have a time of expiration. This is different from the alternatives of the
localStorage
andsessionStorage
. You can emulate the expiration time on those other local options - Can be configured to be sended through
https
. This allow forencoded
andauthentifaction
of transmited data. This reduce the risk of the attack of the man in the middle, this is someone who intercept the message - Can be configured to be sended to domains that are only yours
- Make you less vulnerable to the Cross-Site Request Forgery or CSRF
- Is easier to manage than
localStorage
andsessionStorage
because the user doesn't have the responsability to manage the token anymore. You do this though the server. With this the interoperativity in different services are easier - Finally,
cookies
are no perfect but are more secure thanlocalStorage
andsessionStorage
- The refresh token is not in this class. This refresh token is used primary in the client side, is not sended at any place
-
The technology