Projecte full-stack: React + Node Express + MySQL. Desplegament
Contingut
Introducció
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:
- React + Node Express + MySQL, amb React Components. El codi de github és:
- https://github.com/bezkoder/react-crud-web-api
I per al back-end tenim:
- Node Express + MySQL (raw SQL): Rest API
- https://github.com/bezkoder/nodejs-express-mysql
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
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