├── 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;
--------------------------------------------------------------------------------