/node

Primary LanguageJavaScript

Learning node && backend

DONE

class-1: NODE
  1. 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
  2. OS info
    • OS Info from node:os
    • It can be access to: platform, release, architecture, cpu, free memory, total memory and more
  3. FS stat: isFile, isDirectory, isSize
    • Can now if a something is a file, is directory, the size with node:fs
  4. Read a file: sync, callback, promisify
    • Can read a file sync, with callbacks and using promisify
    • Caveat 🟨: only tested with .txt files
  5. 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
  6. 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
  7. LS: promises, promises-then
    • This is a app that list the files from this folder in a promisify way and in a Sync way
  8. 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
  9. LS advance: thenable, async await, arguments, prompt
    • More advance lswith a thenable, async await, arguments and prompts on terminal
  10. Http server
    • Creation of a http server only with node
  11. Free port method
    • Method to get a free port if the desired is used
class-2: HTTP && Express
  1. 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
    • 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
  2. 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
  3. 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
    • On Express the method app.use(express.json()) ccan be used to make something a json. See the file class-2/3.express.js on line 33 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
  1. 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
  2. Express use path-to-regex
    1. Is possible to put regex in the URL but express use this library: path-to-regex, like this app.get("/movies/:id", fn)
    2. 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
    3. Everytime you can, use path-to-regex because make the regex by you can lead into problems
    4. To know more check the github repository of pillarjs or the express explanation in their documentationr>
  3. 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
        1. On URL: `/movies`
        2. 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
        1. On URL: `/movies/:id` → `/movies/123-456-789`
        2. 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
        1. On URL: `/movies/:id` → `/movies/123-456-789`
        2. 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
  4. 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/ aka mywebsite.com ask to http://localhost:3000 aka API.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 case http://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
    • 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 the http:localhost:3000 and I make a request to http:localhost:3000 no origin header will sent
    • Exist simples and complex methods with CORS:
      • Simples: GET, HEAD and POST
      • Complex: PUT, PATCH and DELETE
        • This methods have something call Preflight, this mean that you need to add a call with the method OPTIONS in order to make them acceptable
    • At the end the problem with CORS is a problem of headers. You should be able to use res.header("Access-Control-Allow-Origin", origin) and res.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 the app.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
class-4: MVC and Deploying of API
  1. Environmental variables
    • This should be always on UPPERCASE
    • On express it can be used like this to deploy it on some service:
      1. const PORT = process.env.PORT ?? 3000
      2. app.listen(PORT, () => { console.log(`Server listening on port http://localhost:${PORT}`)})
  2. Configuration on hosting
    • Normally the host ask you for a start script on the package.json to run the file or maybe it will ask on the configuration
  3. 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 the assert will stop work at some point
      • import allMoviesJSON from "./data/movies.json" with { type: "json" } → Change the assert for with
        1. import fs from "node:fs"
        2. 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)
        1. import { createRequire } from "node:module"
        2. const require = createRequire(import.meta.url)
        3. const allMoviesJSON = require("./data/movies.json")
  4. MVC: Model, View, Controller
    • Exist some debate if the MVC is a Design Pattern or a Architecture Patterns. It seems more like an architecture. Nonetheless, it doesn't explain everything because it doesn't tell you how to implement the View
    • 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 the Controller and after that it will init the View. After that the user throught the View will interact wanting something happen. With that interact of the user the Controller will act asking for the correct data to the Model, generally speaking having the CRUD approach here with them
    • Remember here, from the View is not possible to interact directly with the Model. But is possible indirectly because the user, at the end, make some request to the Model through the Controller
    • 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 the Controll share the same names for the methods. Even sometimes you will need to call more than one Model from the Controller
    • 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 the Model. When it comes from the input from the user, is a good thing to validate the data before to send it to the Model. With this validation you allow the data is correct to be used or to avoid attacks
      • Model: 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 the Controller to make the validation there. Here the validation will stay apply in the Model but it will be used, also, by the Controller
      • With this said: validation on Model and Controller are mandatory, validations on View are optional (very interesting)
  5. Difference between Design Pattern and Architecture Pattern
    • The Design Pattern: is an easy, repeteable, to solve something specific in a part of the code. For example:
      1. Pattern Observer
      2. Pattern Factory
      3. 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
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)
    A database can have only one Intern Level, only one Conceptual level but many External Levels
  • 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: a table is a page, that contain columns and rows. A table can relate to another table using various type of relationships like one-to-one and one-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:
      1. Data Definition Language (DDL): includes statements for defining the database and its objects such as tables, views, triggers, stored procedures, etc
      2. Data Manipulation Language (DML): contains statements for updating and querying data
      3. Data Control Language (DCL): allows you to grant permissions to users to access specific data in the database
  • 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 the rollback to revert the changes. And when you be happy with your changes, you can use the commit; 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 use MySQL 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 or Microsoft SQL Server, MySQL is relatively easy to master
    • MySQL is versatile and can run on various platforms, including UNIX, Linux, and Windows
    • MySQL is renowned for its reliability, scalability, and speed
  • 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:
      1. Reach with the terminal the desired path or know the path of your file
      2. Once you get the path run this on the terminal to open the mySQL Command Line Client: mysqlsh
      3. You should explicty change use the sql shell with \sql
      4. 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
      5. Run the command \. [name_of_script].sql and done
      6. IMPORTANT: ⚡ Running the sql scripts this way will allow you to use the SOURCE command, that comes from the mySQL 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 or function can receive their dependencies from outisde and the inner behavior change depending on how this information is provided

NOW

  • Creation of a database with mySQL and avoiding hackers (good practices)

Pending

  1. Connect mongoDB with express
  • Perform a CRUD with the database using mongoDB
  • Special enphasis on GET with the query
  1. Learn how to use mongoose with express
    • Perform a CRUD with the database using mongoose
    • Special enphasis on GET with the query
  2. Know how to make an dependency injection