Merge pull request #28 from jdrouet/express-mysql
react-express-mysql: fetch version from mysql
This commit is contained in:
		
						commit
						a06e22defb
					
				
					 12 changed files with 672 additions and 306 deletions
				
			
		
							
								
								
									
										1
									
								
								react-express-mysql/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								react-express-mysql/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| node_modules | ||||
|  | @ -1,36 +1,31 @@ | |||
| # if you're doing anything beyond your local machine, please pin this to a specific version at https://hub.docker.com/_/node/ | ||||
| FROM node:10 | ||||
| 
 | ||||
| RUN mkdir -p /opt/app | ||||
| FROM node:lts | ||||
| 
 | ||||
| # set our node environment, either development or production | ||||
| # defaults to production, compose overrides this to development on build and run | ||||
| ARG NODE_ENV=production | ||||
| ENV NODE_ENV $NODE_ENV | ||||
| 
 | ||||
| WORKDIR /code | ||||
| 
 | ||||
| # default to port 80 for node, and 9229 and 9230 (tests) for debug | ||||
| ARG PORT=80 | ||||
| ENV PORT $PORT | ||||
| EXPOSE $PORT 9229 9230 | ||||
| 
 | ||||
| # you'll likely want the latest npm, reguardless of node version, for speed and fixes | ||||
| RUN npm i npm@latest -g | ||||
| 
 | ||||
| # install dependencies first, in a different location for easier app bind mounting for local development | ||||
| WORKDIR /opt | ||||
| COPY package.json package-lock.json* ./ | ||||
| RUN npm install && npm cache clean --force | ||||
| ENV PATH /opt/node_modules/.bin:$PATH | ||||
| COPY package.json /code/package.json | ||||
| COPY package-lock.json /code/package-lock.json | ||||
| RUN npm ci | ||||
| 
 | ||||
| # check every 30s to ensure this service returns HTTP 200 | ||||
| HEALTHCHECK --interval=30s CMD node healthcheck.js | ||||
| HEALTHCHECK --interval=30s \ | ||||
|   CMD node healthcheck.js | ||||
| 
 | ||||
| # copy in our source code last, as it changes the most | ||||
| WORKDIR /opt/app | ||||
| COPY . /opt/app | ||||
| COPY . /code | ||||
| 
 | ||||
| # if you want to use npm start instead, then use `docker run --init in production` | ||||
| # so that signals are passed properly. Note the code in index.js is needed to catch Docker signals | ||||
| # using node here is still more graceful stopping then npm with --init afaik | ||||
| # I still can't come up with a good production way to run with npm and graceful shutdown | ||||
| CMD [ "node", "index.js" ] | ||||
| CMD [ "node", "src/index.js" ] | ||||
|  |  | |||
							
								
								
									
										18
									
								
								react-express-mysql/backend/healthcheck.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								react-express-mysql/backend/healthcheck.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,20 +1,20 @@ | |||
| var http = require("http"); | ||||
| const http = require("http"); | ||||
| 
 | ||||
| var options = { | ||||
| const options = { | ||||
|   timeout: 2000, | ||||
|   host: 'localhost', | ||||
|   host: "localhost", | ||||
|   port: process.env.PORT || 8080, | ||||
|   path: '/healthz' // must be the same as HEALTHCHECK in Dockerfile
 | ||||
|   path: "/healthz" // must be the same as HEALTHCHECK in Dockerfile
 | ||||
| }; | ||||
| 
 | ||||
| var request = http.request(options, (res) => { | ||||
|   console.info('STATUS: ' + res.statusCode); | ||||
|   process.exitCode = (res.statusCode === 200) ? 0 : 1; | ||||
| const request = http.request(options, res => { | ||||
|   console.info("STATUS: " + res.statusCode); | ||||
|   process.exitCode = res.statusCode === 200 ? 0 : 1; | ||||
|   process.exit(); | ||||
| }); | ||||
| 
 | ||||
| request.on('error', function(err) { | ||||
|   console.error('ERROR', err); | ||||
| request.on("error", function(err) { | ||||
|   console.error("ERROR", err); | ||||
|   process.exit(1); | ||||
| }); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										78
									
								
								react-express-mysql/backend/index.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										78
									
								
								react-express-mysql/backend/index.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,78 +0,0 @@ | |||
| // simple node web server that displays hello world
 | ||||
| // optimized for Docker image
 | ||||
| 
 | ||||
| var express = require('express'); | ||||
| // this example uses express web framework so we know what longer build times
 | ||||
| // do and how Dockerfile layer ordering matters. If you mess up Dockerfile ordering
 | ||||
| // you'll see long build times on every code change + build. If done correctly,
 | ||||
| // code changes should be only a few seconds to build locally due to build cache.
 | ||||
| 
 | ||||
| var morgan = require('morgan'); | ||||
| // morgan provides easy logging for express, and by default it logs to stdout
 | ||||
| // which is a best practice in Docker. Friends don't let friends code their apps to
 | ||||
| // do app logging to files in containers.
 | ||||
| 
 | ||||
| // Constants
 | ||||
| const PORT = process.env.PORT || 8080; | ||||
| // if you're not using docker-compose for local development, this will default to 8080
 | ||||
| // to prevent non-root permission problems with 80. Dockerfile is set to make this 80
 | ||||
| // because containers don't have that issue :)
 | ||||
| 
 | ||||
| // Appi
 | ||||
| var app = express(); | ||||
| 
 | ||||
| app.use(morgan('common')); | ||||
| 
 | ||||
| app.get('/', function (req, res) { | ||||
|   res.json({ message: 'Hello Docker World!' }); | ||||
| }); | ||||
| 
 | ||||
| app.get('/healthz', function (req, res) { | ||||
| 	// do app logic here to determine if app is truly healthy
 | ||||
| 	// you should return 200 if healthy, and anything else will fail
 | ||||
| 	// if you want, you should be able to restrict this to localhost (include ipv4 and ipv6)
 | ||||
|   res.send('I am happy and healthy\n'); | ||||
| }); | ||||
| 
 | ||||
| var server = app.listen(PORT, function () { | ||||
|   console.log('Webserver is ready'); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| //
 | ||||
| // need this in docker container to properly exit since node doesn't handle SIGINT/SIGTERM
 | ||||
| // this also won't work on using npm start since:
 | ||||
| // https://github.com/npm/npm/issues/4603
 | ||||
| // https://github.com/npm/npm/pull/10868
 | ||||
| // https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
 | ||||
| // if you want to use npm then start with `docker run --init` to help, but I still don't think it's
 | ||||
| // a graceful shutdown of node process
 | ||||
| //
 | ||||
| 
 | ||||
| // quit on ctrl-c when running docker in terminal
 | ||||
| process.on('SIGINT', function onSigint () { | ||||
| 	console.info('Got SIGINT (aka ctrl-c in docker). Graceful shutdown ', new Date().toISOString()); | ||||
|   shutdown(); | ||||
| }); | ||||
| 
 | ||||
| // quit properly on docker stop
 | ||||
| process.on('SIGTERM', function onSigterm () { | ||||
|   console.info('Got SIGTERM (docker container stop). Graceful shutdown ', new Date().toISOString()); | ||||
|   shutdown(); | ||||
| }) | ||||
| 
 | ||||
| // shut down server
 | ||||
| function shutdown() { | ||||
|   server.close(function onServerClosed (err) { | ||||
|     if (err) { | ||||
|       console.error(err); | ||||
|       process.exitCode = 1; | ||||
| 		} | ||||
| 		process.exit(); | ||||
|   }) | ||||
| } | ||||
| //
 | ||||
| // need above in docker container to properly exit
 | ||||
| //
 | ||||
| 
 | ||||
| module.exports = app; | ||||
							
								
								
									
										668
									
								
								react-express-mysql/backend/package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										668
									
								
								react-express-mysql/backend/package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -4,20 +4,20 @@ | |||
|   "version": "2.0.0", | ||||
|   "description": "Node.js Hello world app using docker features for easy docker-compose local dev and solid production defaults", | ||||
|   "author": "Bret Fisher <bret@bretfisher.com>", | ||||
|   "main": "index.js", | ||||
|   "main": "src/index.js", | ||||
|   "scripts": { | ||||
|     "start": "node index.js", | ||||
|     "dev-docker": "../node_modules/nodemon/bin/nodemon.js --debug=5858", | ||||
|     "dev-host": "nodemon --debug=5858", | ||||
|     "start-watch": "nodemon index.js --inspect=0.0.0.0:9229", | ||||
|     "start-wait-debuger": "nodemon index.js --inspect-brk=0.0.0.0:9229", | ||||
|     "start": "node src/index.js", | ||||
|     "start-watch": "nodemon src/index.js --inspect=0.0.0.0:9229", | ||||
|     "start-wait-debuger": "nodemon src/index.js --inspect-brk=0.0.0.0:9229", | ||||
|     "test": "cross-env NODE_ENV=test PORT=8081 mocha --timeout 10000 --exit --inspect=0.0.0.0:9230", | ||||
|     "test-watch": "nodemon --exec \"npm test\"", | ||||
|     "test-wait-debuger": "cross-env NODE_ENV=test PORT=8081 mocha --no-timeouts --exit --inspect-brk=0.0.0.0:9230" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "express": "^4.16.3", | ||||
|     "morgan": "^1.8.1" | ||||
|     "knex": "^0.20.13", | ||||
|     "morgan": "^1.8.1", | ||||
|     "mysql2": "^2.1.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "chai": "^4.1.2", | ||||
|  |  | |||
							
								
								
									
										20
									
								
								react-express-mysql/backend/src/config.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								react-express-mysql/backend/src/config.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| const fs = require("fs"); | ||||
| 
 | ||||
| const readFileSync = filename => fs.readFileSync(filename).toString("utf8"); | ||||
| 
 | ||||
| // Constants
 | ||||
| module.exports = { | ||||
|   database: { | ||||
|     host: process.env.DATABASE_HOST || "localhost", | ||||
|     port: process.env.DATABASE_PORT, | ||||
|     database: process.env.DATABASE_DB, | ||||
|     user: process.env.DATABASE_USER, | ||||
|     password: process.env.DATABASE_PASSWORD | ||||
|       ? readFileSync(process.env.DATABASE_PASSWORD) | ||||
|       : null | ||||
|   }, | ||||
|   port: process.env.PORT || 8080 | ||||
|   // if you're not using docker-compose for local development, this will default to 8080
 | ||||
|   // to prevent non-root permission problems with 80. Dockerfile is set to make this 80
 | ||||
|   // because containers don't have that issue :)
 | ||||
| }; | ||||
							
								
								
									
										7
									
								
								react-express-mysql/backend/src/database.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								react-express-mysql/backend/src/database.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| const knex = require('knex'); | ||||
| const { database } = require('./config'); | ||||
| 
 | ||||
| module.exports = knex({ | ||||
|   client: 'mysql2', | ||||
|   connection: database, | ||||
| }); | ||||
							
								
								
									
										48
									
								
								react-express-mysql/backend/src/index.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								react-express-mysql/backend/src/index.js
									
										
									
									
										vendored
									
									
										Executable file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| const app = require("./server"); | ||||
| const { port } = require("./config"); | ||||
| 
 | ||||
| const server = app.listen(port, function() { | ||||
|   console.log("Webserver is ready"); | ||||
| }); | ||||
| 
 | ||||
| //
 | ||||
| // need this in docker container to properly exit since node doesn't handle SIGINT/SIGTERM
 | ||||
| // this also won't work on using npm start since:
 | ||||
| // https://github.com/npm/npm/issues/4603
 | ||||
| // https://github.com/npm/npm/pull/10868
 | ||||
| // https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
 | ||||
| // if you want to use npm then start with `docker run --init` to help, but I still don't think it's
 | ||||
| // a graceful shutdown of node process
 | ||||
| //
 | ||||
| 
 | ||||
| // quit on ctrl-c when running docker in terminal
 | ||||
| process.on("SIGINT", function onSigint() { | ||||
|   console.info( | ||||
|     "Got SIGINT (aka ctrl-c in docker). Graceful shutdown ", | ||||
|     new Date().toISOString() | ||||
|   ); | ||||
|   shutdown(); | ||||
| }); | ||||
| 
 | ||||
| // quit properly on docker stop
 | ||||
| process.on("SIGTERM", function onSigterm() { | ||||
|   console.info( | ||||
|     "Got SIGTERM (docker container stop). Graceful shutdown ", | ||||
|     new Date().toISOString() | ||||
|   ); | ||||
|   shutdown(); | ||||
| }); | ||||
| 
 | ||||
| // shut down server
 | ||||
| function shutdown() { | ||||
|   server.close(function onServerClosed(err) { | ||||
|     if (err) { | ||||
|       console.error(err); | ||||
|       process.exit(1); | ||||
|     } | ||||
|     process.exit(0); | ||||
|   }); | ||||
| } | ||||
| //
 | ||||
| // need above in docker container to properly exit
 | ||||
| //
 | ||||
							
								
								
									
										36
									
								
								react-express-mysql/backend/src/server.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								react-express-mysql/backend/src/server.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| // simple node web server that displays hello world
 | ||||
| // optimized for Docker image
 | ||||
| 
 | ||||
| const express = require("express"); | ||||
| // this example uses express web framework so we know what longer build times
 | ||||
| // do and how Dockerfile layer ordering matters. If you mess up Dockerfile ordering
 | ||||
| // you'll see long build times on every code change + build. If done correctly,
 | ||||
| // code changes should be only a few seconds to build locally due to build cache.
 | ||||
| 
 | ||||
| const morgan = require("morgan"); | ||||
| // morgan provides easy logging for express, and by default it logs to stdout
 | ||||
| // which is a best practice in Docker. Friends don't let friends code their apps to
 | ||||
| // do app logging to files in containers.
 | ||||
| 
 | ||||
| const database = require("./database"); | ||||
| 
 | ||||
| // Appi
 | ||||
| const app = express(); | ||||
| 
 | ||||
| app.use(morgan("common")); | ||||
| 
 | ||||
| app.get("/", function(req, res, next) { | ||||
|   database.raw('select VERSION() version') | ||||
|     .then(([rows, columns]) => rows[0]) | ||||
|     .then((row) => res.json({ message: `Hello from MySQL ${row.version}` })) | ||||
|     .catch(next); | ||||
| }); | ||||
| 
 | ||||
| app.get("/healthz", function(req, res) { | ||||
|   // do app logic here to determine if app is truly healthy
 | ||||
|   // you should return 200 if healthy, and anything else will fail
 | ||||
|   // if you want, you should be able to restrict this to localhost (include ipv4 and ipv6)
 | ||||
|   res.send("I am happy and healthy\n"); | ||||
| }); | ||||
| 
 | ||||
| module.exports = app; | ||||
							
								
								
									
										49
									
								
								react-express-mysql/backend/test/sample.js
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								react-express-mysql/backend/test/sample.js
									
										
									
									
										vendored
									
									
								
							|  | @ -1,32 +1,33 @@ | |||
| const app = require('../index'); | ||||
| const chai = require("chai"); | ||||
| const chaiHttp = require("chai-http"); | ||||
| 
 | ||||
| const chai = require('chai'); | ||||
| const chaiHttp = require('chai-http'); | ||||
| const app = require("../src/server"); | ||||
| 
 | ||||
| chai.use(chaiHttp); | ||||
| chai.should(); | ||||
| 
 | ||||
| describe('API /healthz', () => { | ||||
|     it('it should return 200', (done) => { | ||||
|         chai.request(app) | ||||
|             .get('/healthz') | ||||
|             .end((err, res) => { | ||||
|                 res.should.have.status(200); | ||||
|                 done(); | ||||
|             }); | ||||
|     }); | ||||
| describe("API /healthz", () => { | ||||
|   it("it should return 200", done => { | ||||
|     chai | ||||
|       .request(app) | ||||
|       .get("/healthz") | ||||
|       .end((err, res) => { | ||||
|         res.should.have.status(200); | ||||
|         done(); | ||||
|       }); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| describe('API /', () => { | ||||
|     it('it should return Welcome message', (done) => { | ||||
|         chai.request(app) | ||||
|             .get('/') | ||||
|             .end((err, res) => { | ||||
|                 res.should.have.status(200); | ||||
|                 res.should.to.be.html; | ||||
|                 res.text.should.be.equal("Hello Docker World\n"); | ||||
|                 done(); | ||||
|             }); | ||||
|     }); | ||||
| describe("API /", () => { | ||||
|   it("it should return Welcome message", done => { | ||||
|     chai | ||||
|       .request(app) | ||||
|       .get("/") | ||||
|       .end((err, res) => { | ||||
|         res.should.have.status(200); | ||||
|         res.should.to.be.html; | ||||
|         res.text.should.be.equal("Hello Docker World\n"); | ||||
|         done(); | ||||
|       }); | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,17 +5,23 @@ services: | |||
|       args: | ||||
|       - NODE_ENV=development | ||||
|       context: backend | ||||
|     command: ../node_modules/.bin/nodemon --inspect=0.0.0.0:9229 | ||||
|     command: npm run start-watch | ||||
|     environment: | ||||
|       - DATABASE_DB=example | ||||
|       - DATABASE_USER=root | ||||
|       - DATABASE_PASSWORD=/run/secrets/db-password | ||||
|       - DATABASE_HOST=db | ||||
|       - NODE_ENV=development | ||||
|     ports: | ||||
|       - 80:80 | ||||
|       - 9229:9229 | ||||
|       - 9230:9230 | ||||
|     secrets: | ||||
|       - db-password | ||||
|     volumes: | ||||
|       - ./backend:/opt/app:delegated | ||||
|       - ./backend/package.json:/opt/package.json | ||||
|       - ./backend/package-lock.json:/opt/package-lock.json | ||||
|       - ./backend/src:/code/src:ro | ||||
|       - ./backend/package.json:/code/package.json | ||||
|       - ./backend/package-lock.json:/code/package-lock.json | ||||
|       - back-notused:/opt/app/node_modules | ||||
|     networks: | ||||
|       - public | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue