Projecte full-stack: React + Node Express + MySQL. Desplegament

De wikijoan
Salta a la navegació Salta a la cerca

Introducció

Tutorials react express mysql.png

Versió antiga del tutorial:

Referència principal:

És un tutorial full stack. Es tracta de crear una aplicació amb React (front-end) i Node (back-end, API), que crea un CRUD per inserir en la taula tutorials (MySQL) una llista de tutorials.

Per aconseguir aquest objectiu hi ha diferents opcions. Entre les diferents opcions nosaltres farem:

I per al back-end tenim:

Instal·lació en local

Instal·lació del back-end

Primer comencem amb el back-end

$ git clone https://github.com/bezkoder/nodejs-express-mysql
$ cd nodejs-express-mysql/

El primer que haurem de fer és configurar la connexió a la base de dades:

$ joe app/config/db.config.js

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "*******",
  DB: "balmes"
};

L'aplicació utilitzarà la taula tutorials, que en aquesta versió del tutorial s'haurà de crear manualment:

CREATE TABLE IF NOT EXISTS `tutorials` (
`id` INTEGER NOT NULL auto_increment ,
`title` VARCHAR(255),
`description` VARCHAR(255),
`published` TINYINT(1),
`createdAt` DATETIME NOT NULL DEFAULT NOW(),
`updatedAt` DATETIME NOT NULL DEFAULT NOW(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;

Instal·lem totes les dependències:

$ npm install

I ara ja podem arrencar el servei:

$ npm start

> nodejs-express-mysql@1.0.0 start
> node server.js

Server is running on port 8080.


I ara ja funciona la API. (l'alumne pot utilitzar Postman)

1. Create a new Tutorial using POST /tutorials Api

$ curl -i -H "Accept: application/json" -X POST -H "Content-Type: application/json" -d '{ "title":"Titol1","description":"Descripció 1" }' localhost:8080/api/tutorials

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:8081
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 151
ETag: W/"97-RkimZsWUw8GCdReyYgVuLFXsxC8"
Date: Sat, 01 May 2021 21:43:51 GMT
Connection: keep-alive

{"id":1,"title":"Titol1","description":"Descripció 1","published":false,"updatedAt":"2021-05-01T19:07:19.204Z","createdAt":"2021-05-01T19:07:19.204Z"}
i efectivament, ho comprovem directament en el mysql:
mysql> select * from tutorials;
+----+--------+---------------+-----------+---------------------+---------------------+
| id | title  | description   | published | createdAt           | updatedAt           |
+----+--------+---------------+-----------+---------------------+---------------------+
|  1 | Titol1 | Descripció 1  |         0 | 2021-05-01 19:07:19 | 2021-05-01 19:07:19 |
+----+--------+---------------+-----------+---------------------+---------------------+

Està funcionant la API.

2. Retrieve all Tutorials using GET /tutorials Api

$ curl -i -X GET localhost:8080/api/tutorials

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:8081
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 761
ETag: W/"2f9-3kntDat4Q6ay4VVBoijKdyLkqls"
Date: Sat, 01 May 2021 19:15:34 GMT
Connection: keep-alive

[{"id":1,"title":"Titol1","description":"Descripció 1","published":false,"createdAt":"2021-05-01T19:07:19.000Z","updatedAt":"2021-05-01T19:07:19.000Z"},{"id":2,"title":"Titol2","description":"Descripció 2","published":false,"createdAt":"2021-05-01T19:09:26.000Z","updatedAt":"2021-05-01T19:09:26.000Z"},{"id":3,"title":"Titol3","description":"Descripció 3","published":false,"createdAt":"2021-05-01T19:09:35.000Z","updatedAt":"2021-05-01T19:09:35.000Z"},{"id":4,"title":"Titol4","description":"Descripció 4","published":false,"createdAt":"2021-05-01T19:09:42.000Z","updatedAt":"2021-05-01T19:09:42.000Z"},{"id":5,"title":"Titol5","description":"Descripció 5","published":false,"createdAt":"2021-05-01T19:09:50.000Z","updatedAt":"2021-05-01T19:09:50.000Z"}]

3. Retrieve a single Tutorial by id using GET /tutorials/:id Api

$ curl -i localhost:8080/api/tutorials/2
...
{"id":2,"title":"Titol2","description":"Descripció 2","published":false,"createdAt":"2021-05-01T19:09:26.000Z","updatedAt":"2021-05-01T19:09:26.000Z"}

4. Update a Tutorial using PUT /tutorials/:id Api

$ curl -i -H "Accept: application/json" -X PUT -H "Content-Type: application/json" -d '{ "published":"true"}' localhost:8080/api/tutorials/3
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:8081
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 48
ETag: W/"30-eLrskyV5K+qpOebje/ICJS9bwCQ"
Date: Sat, 01 May 2021 21:41:52 GMT
Connection: keep-alive

{"message":"Tutorial was updated successfully."}

5. Find all Tutorials which title contains ‘node’: GET /tutorials?title=node

$ curl -i -X GET localhost:8080/api/tutorials/title=4
(no funciona?)

6. Find all published Tutorials using GET /tutorials/published Api

$ curl -i -X GET localhost:8080/api/tutorials/published
...
[{"id":3,"title":"Titol3","description":"Descripció 3","published":true,"createdAt":"2021-05-01T19:09:35.000Z","updatedAt":"2021-05-01T21:41:52.000Z"}]

7. Delete a Tutorial using DELETE /tutorials/:id Api

$ curl -i -X DELETE localhost:8080/api/tutorials/5
...
{"message":"Tutorial was deleted successfully!"}

8. Delete all Tutorials using DELETE /tutorials Api

$ curl -i -X DELETE localhost:8080/api/tutorials
...
{"message":"5 Tutorials were deleted successfully!"}

Instal·lació del front-end

Un cop tenim instal·lat i funcionant el back-end (la API), el deixem engegat en la seva consola, i obrim una altra consola on instal·larem el front-end de React.

React + Node Express + MySQL (utilitzant Components). Github:

$ git clone https://github.com/bezkoder/react-crud-web-api

$ cd react-crud-web-api/
$ npm install

I arrenquem:

$ npm start

Compiled successfully!

You can now view react-crud in the browser.

  Local:            http://localhost:8081
  On Your Network:  http://192.168.43.83:8081

Note that the development build is not optimized.
To create a production build, use yarn build.

I ja tenim l'aplicació funcionant.

Desplegament

Com es comenta, per fer el development build del front-end podem fer: yarn build, però també ho podem fer amb:

$ npm run build
...
Creating an optimized production build...
...
Compiled successfully.

File sizes after gzip:

  52.62 KB  build/static/js/2.35457f30.chunk.js
  22.44 KB  build/static/css/2.47e06e2e.chunk.css
  2.39 KB   build/static/js/main.35b1a7a5.chunk.js
  774 B     build/static/js/runtime-main.efee8004.js
  144 B     build/static/css/main.b5fec8d3.chunk.css

The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.

Aquesta última frase és important. Modifiquem el package.json i afegim la directiva homepage:

{
  "name": "react-crud",
  "version": "0.1.0",
  "private": true,
  "homepage": "./",
  ...

Desplegar en local

Recordar que hem de tenir el servidor node arrencat.

En local hem de configurar la ruta Apache per tal de què apunti al fitxer build/index.html:

   Alias /tutorials "/home/joan/M06_WEC_2122/UF2/react-crud-web-api/build/"
   <Directory "/home/joan/M06_WEC_2122/UF2/react-crud-web-api/build/">
       Options Indexes MultiViews FollowSymLinks
       AllowOverride None
       Require all granted
       DirectoryIndex index.html default.html index.php
   </Directory>

L'alumne és possible que utilitzi el XAMP o similar. Ha de saber configurar-lo.

$ sudo /etc/init.d/apache2 restart

Es veu tot el front-end, però no es mostra la llista de tutorials. Motiu i solució:

En el server.js del back-end, canviar el CORS origin: (el nostre Apache funciona pel port 80)

var corsOptions = {
  origin: "http://localhost:8081"
};

per

var corsOptions = {
  origin: "http://localhost"
};

Desplegar en el VPS del Jaume Balmes

Tutorials en el nuvol.png

De la part del servidor no te n'has de preocupar. Només hi haurà un servidor i una base de dades. D'això se n'encarrega el professor. El professor, en el server.js, ha fet el següent canvi:


var corsOptions = {
  origin: "http://vps-89148e22.vps.ovh.net"
};

Amb aquest canvi la API funciona:

$ curl -i -H "Accept: application/json" -X POST -H "Content-Type: application/json" -d '{ "title":"Titol1","description":"Descripció 1" }' http://vps-89148e22.vps.ovh.net:8080/api/tutorials
curl -i -X GET http://vps-89148e22.vps.ovh.net:8080/api/tutorials

Només t'has de preocupar de desplegar el front-end.

Però el que sí que has de saber són les dades de connexió a la base de dades:

*servidor mysql: localhost
*usuari: alumne
*password: keiL2lai
*base de dades: balmes

I els canvis que sí que afecten al front-end són:

script ./src/http-common.js:

export default axios.create({
  baseURL: "http://vps-89148e22.vps.ovh.net:8080/api",
  headers: {
    "Content-type": "application/json"
  }
});

Dins del /home del teu servidor crearàs la carpeta tutorials_app, de manera que la ruta del teu projecte serà:

  • /home/nom_usuari/tutorials_app/

script App.js:

class App extends Component {
  render() {
    return (
      <div>
        <nav className="navbar navbar-expand navbar-dark bg-dark">
          <Link to={"/nom_usuari/tutorials_app/tutorials"} className="navbar-brand">
            bezKoder
          </Link>
          <div className="navbar-nav mr-auto">
            <li className="nav-item">
              <Link to={"/nom_usuari/tutorials_app/tutorials"} className="nav-link">
                Tutorials
              </Link>
            </li>
            <li className="nav-item">
              <Link to={"/nom_usuari/tutorials_app/add"} className="nav-link">
                Add
              </Link>
            </li>
          </div>
        </nav>

        <div className="container mt-3">
          <Switch>
            <Route exact path={["/nom_usuari/tutorials_app/", "/joan/tutorials_app/tutorials"]} component={TutorialsList} />
            <Route exact path="/nom_usuari/tutorials_app/add" component={AddTutorial} />
            <Route path="/nom_usuari/tutorials_app/tutorials/:id" component={Tutorial} />
          </Switch>
        </div>
      </div>
    );
  }
}

script components/tutorials-list.component.js:

              <Link
                to={"/nom_usuari/tutorials_app/tutorials/" + currentTutorial.id}
                className="badge badge-warning"
              >
                Edit
              </Link>

Fas el build del teu projecte i envies el build al servidor:

$ npm run build
$ cd build
$ scp -r * nom_usuari@vps-89148e22.vps.ovh.net:/home/nom_usuari/html/tutorials_app/

I amb tots aquests canvis l'aplicació està disponible:

i no entra en conflicte amb les aplicacions dels teus companys. Això sí, totes les aplicacions ataquen la mateixa base de dades.

NOTA: En el servidor el servidor ha d'estar contínuament engegat. Per tal de què no ocupi una finestra de consola oberta, en el servidor s'utilitza l'opció:

$ npm start &
o bé
node server &

NOTA: no acaba de funcionar. Mirar:

Step3: Installing PM2

Next let’s install PM2, a process manager for Node.js applications. PM2 makes it possible to daemonize applications so that they will run in the background as a service.

$ sudo npm install pm2 -g
$ pm2 start server.js

...
PM2] Spawning PM2 daemon with pm2_home=/home/joan/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/joan/nodejs-express-mysql/server.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ server             │ fork     │ 0    │ online    │ 0%       │ 35.5mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

Efectivament el servei està iniciat:

$ ps aux | grep node
joan      371125  0.6  1.3 639784 52848 ?        Ssl  18:05   0:00 node /home/joan/nodejs-express-mysql/server.js

creat per Joan Quintana Compte, abril 2022