├── README.md ├── client ├── Dockerfile ├── package-lock.json ├── package.json ├── public │ └── index.html └── src │ ├── App.css │ ├── App.js │ └── index.js ├── docker-compose.yml ├── nginx ├── Dockerfile └── default.conf ├── server ├── Dockerfile ├── index.js ├── package-lock.json └── package.json └── setup.sql /README.md: -------------------------------------------------------------------------------- 1 | # Build-and-Dockerize-a-Full-stack-React-app-with-Node.js-MySQL-and-Nginx-for-reverse-proxy 2 | 3 | Run `npm i` inside the client directory 4 | 5 | Run `npm i` inside the server directory 6 | 7 | Run `docker-compose up --build` inside the mainn project directory 8 | 9 | Access the Adminer using route `http://localhost:8000/`. 10 | 11 | 12 | To log in, use `mysql_db` as the server Username as `root` and password as `MYSQL_ROOT_PASSWORD`. 13 | 14 | To start interacting with the application, open `http://localhost:3050/` on a browser. 15 | 16 | Check out the step by step explained guide [here](https://www.section.io/engineering-education/build-and-dockerize-a-full-stack-react-app-with-nodejs-and-nginx/) 17 | 18 | https://www.section.io/engineering-education/build-and-dockerize-a-full-stack-react-app-with-nodejs-and-nginx/ 19 | -------------------------------------------------------------------------------- /client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | WORKDIR /app 3 | COPY package.json ./ 4 | COPY package-lock.json ./ 5 | COPY ./ ./ 6 | RUN npm i 7 | CMD ["npm", "run", "start"] -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.14.1", 7 | "@testing-library/react": "^11.2.7", 8 | "@testing-library/user-event": "^12.8.3", 9 | "axios": "^0.21.1", 10 | "bootstrap": "^5.0.2", 11 | "react": "^17.0.2", 12 | "react-bootstrap": "^1.6.1", 13 | "react-dom": "^17.0.2", 14 | "react-scripts": "4.0.3", 15 | "web-vitals": "^1.1.2" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | CRUD Application 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /client/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .form{ 6 | display: inline-block; 7 | justify-content: center; 8 | } 9 | 10 | .form input{ 11 | width: 250px; 12 | margin: 10px; 13 | } -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | /* eslint-disable no-restricted-globals */ 3 | import React, { Component } from 'react'; 4 | import './App.css'; 5 | import axios from 'axios'; 6 | import { Button, Container, Card, Row } from 'react-bootstrap' 7 | 8 | class App extends Component { 9 | constructor(props) { 10 | super(props) 11 | this.state = { 12 | setBookName: '', 13 | setReview: '', 14 | fetchData: [], 15 | reviewUpdate: '' 16 | } 17 | } 18 | 19 | handleChange = (event) => { 20 | let nam = event.target.name; 21 | let val = event.target.value 22 | this.setState({ 23 | [nam]: val 24 | }) 25 | } 26 | 27 | handleChange2 = (event) => { 28 | this.setState({ 29 | reviewUpdate: event.target.value 30 | }) 31 | } 32 | 33 | componentDidMount() { 34 | axios.get("/api/get") 35 | .then((response) => { 36 | this.setState({ 37 | fetchData: response.data 38 | }) 39 | }) 40 | } 41 | 42 | submit = () => { 43 | axios.post('/api/insert', this.state) 44 | .then(() => { alert('success post') }) 45 | console.log(this.state) 46 | document.location.reload(); 47 | } 48 | 49 | delete = (id) => { 50 | if (confirm("Do you want to delete? ")) { 51 | axios.delete(`/api/delete/${id}`) 52 | document.location.reload() 53 | } 54 | } 55 | 56 | edit = (id) => { 57 | axios.put(`/api/update/${id}`, this.state) 58 | document.location.reload(); 59 | } 60 | render() { 61 | 62 | let card = this.state.fetchData.map((val, key) => { 63 | return ( 64 | 65 | 66 | 67 | {val.book_name} 68 | 69 | {val.book_review} 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | ) 78 | }) 79 | 80 | return ( 81 |
82 |

Dockerized Fullstack React Application

83 |
84 | 85 | 86 |
87 | 88 |

89 | 90 | 91 | 92 | {card} 93 | 94 | 95 |
96 | ); 97 | } 98 | } 99 | export default App; -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import 'bootstrap/dist/css/bootstrap.min.css'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); 10 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | x-common-variables: &common-variables 4 | MYSQL_DATABASE: books 5 | MYSQL_USER: MYSQL_USER 6 | MYSQL_PASSWORD: MYSQL_PASSWORD 7 | 8 | services: 9 | mysql_db: 10 | image: mysql 11 | restart: always 12 | cap_add: 13 | - SYS_NICE 14 | volumes: 15 | - "./setup.sql:/docker-entrypoint-initdb.d/setup.sql" 16 | ports: 17 | - "9906:3306" 18 | environment: 19 | <<: *common-variables 20 | MYSQL_ROOT_PASSWORD: MYSQL_ROOT_PASSWORD 21 | MYSQL_HOST: localhost 22 | 23 | nginx: 24 | depends_on: 25 | - api 26 | - client 27 | restart: always 28 | build: 29 | dockerfile: Dockerfile 30 | context: ./nginx 31 | ports: 32 | - "3050:80" 33 | 34 | api: 35 | build: 36 | dockerfile: Dockerfile 37 | context: "./server" 38 | depends_on: 39 | - mysql_db 40 | volumes: 41 | - /app/node_modules 42 | - ./server:/app 43 | environment: 44 | <<: *common-variables 45 | MYSQL_HOST_IP: mysql_db 46 | 47 | client: 48 | stdin_open: true 49 | environment: 50 | - CHOKIDAR_USEPOLLING=true 51 | build: 52 | dockerfile: Dockerfile 53 | context: ./client 54 | volumes: 55 | - /app/node_modules 56 | - ./client:/app 57 | 58 | adminer: 59 | image: adminer:latest 60 | restart: unless-stopped 61 | ports: 62 | - 8000:8080 63 | depends_on: 64 | - mysql_db 65 | environment: 66 | ADMINER_DEFAULT_SERVER: mysql_db -------------------------------------------------------------------------------- /nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | COPY ./default.conf /etc/nginx/conf.d/default.conf 3 | -------------------------------------------------------------------------------- /nginx/default.conf: -------------------------------------------------------------------------------- 1 | upstream client { 2 | server client:3000; 3 | } 4 | 5 | upstream api { 6 | server api:3001; 7 | } 8 | 9 | server { 10 | listen 80; 11 | 12 | location / { 13 | proxy_pass http://client; 14 | } 15 | 16 | location /sockjs-node { 17 | proxy_pass http://client; 18 | proxy_http_version 1.1; 19 | proxy_set_header Upgrade $http_upgrade; 20 | proxy_set_header Connection "Upgrade"; 21 | } 22 | 23 | location /api { 24 | rewrite /api/(.*) /$1 break; 25 | proxy_pass http://api; 26 | } 27 | } -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | WORKDIR /app 3 | COPY package.json ./ 4 | COPY package-lock.json ./ 5 | COPY ./ ./ 6 | RUN npm i 7 | CMD ["npm", "run", "start"] -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mysql = require('mysql2'); 3 | const cors = require('cors'); 4 | const app = express(); 5 | 6 | // Add mysql database connection 7 | const db = mysql.createPool({ 8 | host: 'mysql_db', // the host name MYSQL_DATABASE: node_mysql 9 | user: 'MYSQL_USER', // database user MYSQL_USER: MYSQL_USER 10 | password: 'MYSQL_PASSWORD', // database user password MYSQL_PASSWORD: MYSQL_PASSWORD 11 | database: 'books' // database name MYSQL_HOST_IP: mysql_db 12 | }) 13 | 14 | // Enable cors security headers 15 | app.use(cors()) 16 | 17 | // add an express method to parse the POST method 18 | app.use(express.json()) 19 | app.use(express.urlencoded({ extended: true })); 20 | 21 | // home page 22 | app.get('/', (req, res) => { 23 | res.send('Hi There') 24 | }); 25 | 26 | // get all of the books in the database 27 | app.get('/get', (req, res) => { 28 | const SelectQuery = " SELECT * FROM books_reviews"; 29 | db.query(SelectQuery, (err, result) => { 30 | res.send(result) 31 | }) 32 | }) 33 | 34 | // add a book to the database 35 | app.post("/insert", (req, res) => { 36 | const bookName = req.body.setBookName; 37 | const bookReview = req.body.setReview; 38 | const InsertQuery = "INSERT INTO books_reviews (book_name, book_review) VALUES (?, ?)"; 39 | db.query(InsertQuery, [bookName, bookReview], (err, result) => { 40 | console.log(result) 41 | }) 42 | }) 43 | 44 | // delete a book from the database 45 | app.delete("/delete/:bookId", (req, res) => { 46 | const bookId = req.params.bookId; 47 | const DeleteQuery = "DELETE FROM books_reviews WHERE id = ?"; 48 | db.query(DeleteQuery, bookId, (err, result) => { 49 | if (err) console.log(err); 50 | }) 51 | }) 52 | 53 | // update a book review 54 | app.put("/update/:bookId", (req, res) => { 55 | const bookReview = req.body.reviewUpdate; 56 | const bookId = req.params.bookId; 57 | const UpdateQuery = "UPDATE books_reviews SET book_review = ? WHERE id = ?"; 58 | db.query(UpdateQuery, [bookReview, bookId], (err, result) => { 59 | if (err) console.log(err) 60 | }) 61 | }) 62 | 63 | app.listen('3001', () => { }) -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "accepts": { 6 | "version": "1.3.7", 7 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 8 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 9 | "requires": { 10 | "mime-types": "~2.1.24", 11 | "negotiator": "0.6.2" 12 | } 13 | }, 14 | "array-flatten": { 15 | "version": "1.1.1", 16 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 17 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 18 | }, 19 | "body-parser": { 20 | "version": "1.19.0", 21 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 22 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 23 | "requires": { 24 | "bytes": "3.1.0", 25 | "content-type": "~1.0.4", 26 | "debug": "2.6.9", 27 | "depd": "~1.1.2", 28 | "http-errors": "1.7.2", 29 | "iconv-lite": "0.4.24", 30 | "on-finished": "~2.3.0", 31 | "qs": "6.7.0", 32 | "raw-body": "2.4.0", 33 | "type-is": "~1.6.17" 34 | } 35 | }, 36 | "bytes": { 37 | "version": "3.1.0", 38 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 39 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 40 | }, 41 | "content-disposition": { 42 | "version": "0.5.3", 43 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 44 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 45 | "requires": { 46 | "safe-buffer": "5.1.2" 47 | } 48 | }, 49 | "content-type": { 50 | "version": "1.0.4", 51 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 52 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 53 | }, 54 | "cookie": { 55 | "version": "0.4.0", 56 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 57 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 58 | }, 59 | "cookie-signature": { 60 | "version": "1.0.6", 61 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 62 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 63 | }, 64 | "cors": { 65 | "version": "2.8.5", 66 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 67 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 68 | "requires": { 69 | "object-assign": "^4", 70 | "vary": "^1" 71 | } 72 | }, 73 | "debug": { 74 | "version": "2.6.9", 75 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 76 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 77 | "requires": { 78 | "ms": "2.0.0" 79 | } 80 | }, 81 | "denque": { 82 | "version": "1.5.0", 83 | "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", 84 | "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" 85 | }, 86 | "depd": { 87 | "version": "1.1.2", 88 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 89 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 90 | }, 91 | "destroy": { 92 | "version": "1.0.4", 93 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 94 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 95 | }, 96 | "ee-first": { 97 | "version": "1.1.1", 98 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 99 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 100 | }, 101 | "encodeurl": { 102 | "version": "1.0.2", 103 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 104 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 105 | }, 106 | "escape-html": { 107 | "version": "1.0.3", 108 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 109 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 110 | }, 111 | "etag": { 112 | "version": "1.8.1", 113 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 114 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 115 | }, 116 | "express": { 117 | "version": "4.17.1", 118 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 119 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 120 | "requires": { 121 | "accepts": "~1.3.7", 122 | "array-flatten": "1.1.1", 123 | "body-parser": "1.19.0", 124 | "content-disposition": "0.5.3", 125 | "content-type": "~1.0.4", 126 | "cookie": "0.4.0", 127 | "cookie-signature": "1.0.6", 128 | "debug": "2.6.9", 129 | "depd": "~1.1.2", 130 | "encodeurl": "~1.0.2", 131 | "escape-html": "~1.0.3", 132 | "etag": "~1.8.1", 133 | "finalhandler": "~1.1.2", 134 | "fresh": "0.5.2", 135 | "merge-descriptors": "1.0.1", 136 | "methods": "~1.1.2", 137 | "on-finished": "~2.3.0", 138 | "parseurl": "~1.3.3", 139 | "path-to-regexp": "0.1.7", 140 | "proxy-addr": "~2.0.5", 141 | "qs": "6.7.0", 142 | "range-parser": "~1.2.1", 143 | "safe-buffer": "5.1.2", 144 | "send": "0.17.1", 145 | "serve-static": "1.14.1", 146 | "setprototypeof": "1.1.1", 147 | "statuses": "~1.5.0", 148 | "type-is": "~1.6.18", 149 | "utils-merge": "1.0.1", 150 | "vary": "~1.1.2" 151 | } 152 | }, 153 | "finalhandler": { 154 | "version": "1.1.2", 155 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 156 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 157 | "requires": { 158 | "debug": "2.6.9", 159 | "encodeurl": "~1.0.2", 160 | "escape-html": "~1.0.3", 161 | "on-finished": "~2.3.0", 162 | "parseurl": "~1.3.3", 163 | "statuses": "~1.5.0", 164 | "unpipe": "~1.0.0" 165 | } 166 | }, 167 | "forwarded": { 168 | "version": "0.2.0", 169 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 170 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 171 | }, 172 | "fresh": { 173 | "version": "0.5.2", 174 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 175 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 176 | }, 177 | "generate-function": { 178 | "version": "2.3.1", 179 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 180 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 181 | "requires": { 182 | "is-property": "^1.0.2" 183 | } 184 | }, 185 | "http-errors": { 186 | "version": "1.7.2", 187 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 188 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 189 | "requires": { 190 | "depd": "~1.1.2", 191 | "inherits": "2.0.3", 192 | "setprototypeof": "1.1.1", 193 | "statuses": ">= 1.5.0 < 2", 194 | "toidentifier": "1.0.0" 195 | } 196 | }, 197 | "iconv-lite": { 198 | "version": "0.4.24", 199 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 200 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 201 | "requires": { 202 | "safer-buffer": ">= 2.1.2 < 3" 203 | } 204 | }, 205 | "inherits": { 206 | "version": "2.0.3", 207 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 208 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 209 | }, 210 | "ipaddr.js": { 211 | "version": "1.9.1", 212 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 213 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 214 | }, 215 | "is-property": { 216 | "version": "1.0.2", 217 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 218 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" 219 | }, 220 | "long": { 221 | "version": "4.0.0", 222 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 223 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 224 | }, 225 | "lru-cache": { 226 | "version": "6.0.0", 227 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 228 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 229 | "requires": { 230 | "yallist": "^4.0.0" 231 | } 232 | }, 233 | "media-typer": { 234 | "version": "0.3.0", 235 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 236 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 237 | }, 238 | "merge-descriptors": { 239 | "version": "1.0.1", 240 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 241 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 242 | }, 243 | "methods": { 244 | "version": "1.1.2", 245 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 246 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 247 | }, 248 | "mime": { 249 | "version": "1.6.0", 250 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 251 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 252 | }, 253 | "mime-db": { 254 | "version": "1.48.0", 255 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", 256 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" 257 | }, 258 | "mime-types": { 259 | "version": "2.1.31", 260 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", 261 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", 262 | "requires": { 263 | "mime-db": "1.48.0" 264 | } 265 | }, 266 | "ms": { 267 | "version": "2.0.0", 268 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 269 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 270 | }, 271 | "mysql2": { 272 | "version": "2.2.5", 273 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", 274 | "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", 275 | "requires": { 276 | "denque": "^1.4.1", 277 | "generate-function": "^2.3.1", 278 | "iconv-lite": "^0.6.2", 279 | "long": "^4.0.0", 280 | "lru-cache": "^6.0.0", 281 | "named-placeholders": "^1.1.2", 282 | "seq-queue": "^0.0.5", 283 | "sqlstring": "^2.3.2" 284 | }, 285 | "dependencies": { 286 | "iconv-lite": { 287 | "version": "0.6.3", 288 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 289 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 290 | "requires": { 291 | "safer-buffer": ">= 2.1.2 < 3.0.0" 292 | } 293 | } 294 | } 295 | }, 296 | "named-placeholders": { 297 | "version": "1.1.2", 298 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", 299 | "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", 300 | "requires": { 301 | "lru-cache": "^4.1.3" 302 | }, 303 | "dependencies": { 304 | "lru-cache": { 305 | "version": "4.1.5", 306 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 307 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 308 | "requires": { 309 | "pseudomap": "^1.0.2", 310 | "yallist": "^2.1.2" 311 | } 312 | }, 313 | "yallist": { 314 | "version": "2.1.2", 315 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 316 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 317 | } 318 | } 319 | }, 320 | "negotiator": { 321 | "version": "0.6.2", 322 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 323 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 324 | }, 325 | "object-assign": { 326 | "version": "4.1.1", 327 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 328 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 329 | }, 330 | "on-finished": { 331 | "version": "2.3.0", 332 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 333 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 334 | "requires": { 335 | "ee-first": "1.1.1" 336 | } 337 | }, 338 | "parseurl": { 339 | "version": "1.3.3", 340 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 341 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 342 | }, 343 | "path-to-regexp": { 344 | "version": "0.1.7", 345 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 346 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 347 | }, 348 | "proxy-addr": { 349 | "version": "2.0.7", 350 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 351 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 352 | "requires": { 353 | "forwarded": "0.2.0", 354 | "ipaddr.js": "1.9.1" 355 | } 356 | }, 357 | "pseudomap": { 358 | "version": "1.0.2", 359 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 360 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 361 | }, 362 | "qs": { 363 | "version": "6.7.0", 364 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 365 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 366 | }, 367 | "range-parser": { 368 | "version": "1.2.1", 369 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 370 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 371 | }, 372 | "raw-body": { 373 | "version": "2.4.0", 374 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 375 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 376 | "requires": { 377 | "bytes": "3.1.0", 378 | "http-errors": "1.7.2", 379 | "iconv-lite": "0.4.24", 380 | "unpipe": "1.0.0" 381 | } 382 | }, 383 | "safe-buffer": { 384 | "version": "5.1.2", 385 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 386 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 387 | }, 388 | "safer-buffer": { 389 | "version": "2.1.2", 390 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 391 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 392 | }, 393 | "send": { 394 | "version": "0.17.1", 395 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 396 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 397 | "requires": { 398 | "debug": "2.6.9", 399 | "depd": "~1.1.2", 400 | "destroy": "~1.0.4", 401 | "encodeurl": "~1.0.2", 402 | "escape-html": "~1.0.3", 403 | "etag": "~1.8.1", 404 | "fresh": "0.5.2", 405 | "http-errors": "~1.7.2", 406 | "mime": "1.6.0", 407 | "ms": "2.1.1", 408 | "on-finished": "~2.3.0", 409 | "range-parser": "~1.2.1", 410 | "statuses": "~1.5.0" 411 | }, 412 | "dependencies": { 413 | "ms": { 414 | "version": "2.1.1", 415 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 416 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 417 | } 418 | } 419 | }, 420 | "seq-queue": { 421 | "version": "0.0.5", 422 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 423 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 424 | }, 425 | "serve-static": { 426 | "version": "1.14.1", 427 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 428 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 429 | "requires": { 430 | "encodeurl": "~1.0.2", 431 | "escape-html": "~1.0.3", 432 | "parseurl": "~1.3.3", 433 | "send": "0.17.1" 434 | } 435 | }, 436 | "setprototypeof": { 437 | "version": "1.1.1", 438 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 439 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 440 | }, 441 | "sqlstring": { 442 | "version": "2.3.2", 443 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", 444 | "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" 445 | }, 446 | "statuses": { 447 | "version": "1.5.0", 448 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 449 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 450 | }, 451 | "toidentifier": { 452 | "version": "1.0.0", 453 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 454 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 455 | }, 456 | "type-is": { 457 | "version": "1.6.18", 458 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 459 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 460 | "requires": { 461 | "media-typer": "0.3.0", 462 | "mime-types": "~2.1.24" 463 | } 464 | }, 465 | "unpipe": { 466 | "version": "1.0.0", 467 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 468 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 469 | }, 470 | "utils-merge": { 471 | "version": "1.0.1", 472 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 473 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 474 | }, 475 | "vary": { 476 | "version": "1.1.2", 477 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 478 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 479 | }, 480 | "yallist": { 481 | "version": "4.0.0", 482 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 483 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 484 | } 485 | } 486 | } 487 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "cors": "^2.8.5", 8 | "express": "^4.17.1", 9 | "mysql2": "^2.2.5" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "start": "node index.js", 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC" 19 | } 20 | -------------------------------------------------------------------------------- /setup.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `books_reviews` ( 2 | `id` int(11) NOT NULL AUTO_INCREMENT, 3 | `book_name` varchar(50) NOT NULL, 4 | `book_review` varchar(50) NOT NULL, 5 | PRIMARY KEY (`id`) 6 | ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1; --------------------------------------------------------------------------------