Browse Source

First commit

master
Alfred 2 years ago
commit
50ae47a455
13 changed files with 435 additions and 0 deletions
  1. 14
    0
      .eslintrc.json
  2. 78
    0
      .gitignore
  3. 26
    0
      Dockerfile
  4. 20
    0
      LICENSE
  5. 1
    0
      Procfile
  6. 61
    0
      README.md
  7. 56
    0
      package.json
  8. 64
    0
      src/api/index.js
  9. 4
    0
      src/db.js
  10. 37
    0
      src/index.js
  11. 43
    0
      src/lib/util.js
  12. 22
    0
      src/managers/appmanager.js
  13. 9
    0
      src/middleware/index.js

+ 14
- 0
.eslintrc.json View File

@@ -0,0 +1,14 @@
1
+{
2
+  "parserOptions": {
3
+    "ecmaVersion": 6,
4
+    "sourceType": "module",
5
+    "ecmaFeatures": {
6
+      "jsx": true
7
+    }
8
+  },
9
+  // "extends": "eslint:all",
10
+  "extends": "eslint:recommended",
11
+  "rules": {
12
+    "semi": "error"
13
+  }
14
+}

+ 78
- 0
.gitignore View File

@@ -0,0 +1,78 @@
1
+# Logs
2
+logs
3
+*.log
4
+npm-debug.log*
5
+yarn-debug.log*
6
+yarn-error.log*
7
+
8
+# Runtime data
9
+pids
10
+*.pid
11
+*.seed
12
+*.pid.lock
13
+
14
+# Directory for instrumented libs generated by jscoverage/JSCover
15
+lib-cov
16
+
17
+# Coverage directory used by tools like istanbul
18
+coverage
19
+
20
+# nyc test coverage
21
+.nyc_output
22
+
23
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24
+.grunt
25
+
26
+# Bower dependency directory (https://bower.io/)
27
+bower_components
28
+
29
+# node-waf configuration
30
+.lock-wscript
31
+
32
+# Compiled binary addons (http://nodejs.org/api/addons.html)
33
+build/Release
34
+
35
+# Dependency directories
36
+node_modules/
37
+jspm_packages/
38
+
39
+# Typescript v1 declaration files
40
+typings/
41
+
42
+# Optional npm cache directory
43
+.npm
44
+package-lock.json
45
+
46
+# Optional eslint cache
47
+.eslintcache
48
+
49
+# Optional REPL history
50
+.node_repl_history
51
+
52
+# Output of 'npm pack'
53
+*.tgz
54
+
55
+# Yarn Integrity file
56
+.yarn-integrity
57
+
58
+# dotenv environment variables file
59
+.env
60
+
61
+# express-es6-rest-api
62
+/dist
63
+/logs
64
+/npm-debug.log
65
+/node_modules
66
+.DS_Store
67
+
68
+# VSCode
69
+.vscode
70
+
71
+# WebStorm
72
+*.idea
73
+
74
+# Data Bases
75
+**/*.sqlite
76
+
77
+# Config files
78
+config/*

+ 26
- 0
Dockerfile View File

@@ -0,0 +1,26 @@
1
+FROM alpine:3.4
2
+
3
+# File Author / Maintainer
4
+LABEL authors="Zouhir Chahoud <zouhir@zouhir.org>"
5
+
6
+# Update & install required packages
7
+RUN apk add --update nodejs bash git
8
+
9
+# Install app dependencies
10
+COPY package.json /www/package.json
11
+RUN cd /www; npm install
12
+
13
+# Copy app source
14
+COPY . /www
15
+
16
+# Set work directory to /www
17
+WORKDIR /www
18
+
19
+# set your port
20
+ENV PORT 8080
21
+
22
+# expose the port to outside world
23
+EXPOSE  8080
24
+
25
+# start command as per package.json
26
+CMD ["npm", "start"]

+ 20
- 0
LICENSE View File

@@ -0,0 +1,20 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2016 Jason Miller
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+this software and associated documentation files (the "Software"), to deal in
7
+the Software without restriction, including without limitation the rights to
8
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+the Software, and to permit persons to whom the Software is furnished to do so,
10
+subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 1
- 0
Procfile View File

@@ -0,0 +1 @@
1
+web: npm start

+ 61
- 0
README.md View File

@@ -0,0 +1,61 @@
1
+Express & ES6 REST API Boilerplate
2
+==================================
3
+
4
+[![bitHound Score](https://www.bithound.io/github/developit/express-es6-rest-api/badges/score.svg)](https://www.bithound.io/github/developit/express-es6-rest-api)
5
+
6
+This is a straightforward boilerplate for building REST APIs with ES6 and Express.
7
+
8
+- ES6 support via [babel](https://babeljs.io)
9
+- REST resources as middleware via [resource-router-middleware](https://github.com/developit/resource-router-middleware)
10
+- CORS support via [cors](https://github.com/troygoode/node-cors)
11
+- Body Parsing via [body-parser](https://github.com/expressjs/body-parser)
12
+
13
+> Tip: If you are using [Mongoose](https://github.com/Automattic/mongoose), you can automatically expose your Models as REST resources using [restful-mongoose](https://git.io/restful-mongoose).
14
+
15
+Getting Started
16
+---------------
17
+
18
+```sh
19
+# clone it
20
+git clone git@github.com:developit/express-es6-rest-api.git
21
+cd express-es6-rest-api
22
+
23
+# Make it your own
24
+rm -rf .git && git init && npm init
25
+
26
+# Install dependencies
27
+npm install
28
+
29
+# Start development live-reload server
30
+PORT=8080 npm run dev
31
+
32
+# Start production server:
33
+PORT=8080 npm start
34
+```
35
+Docker Support
36
+------
37
+```sh
38
+cd express-es6-rest-api
39
+
40
+# Build your docker
41
+docker build -t es6/api-service .
42
+#            ^      ^           ^
43
+#          tag  tag name      Dockerfile location
44
+
45
+# run your docker
46
+docker run -p 8080:8080 es6/api-service
47
+#                 ^            ^
48
+#          bind the port    container tag
49
+#          to your host
50
+#          machine port   
51
+
52
+```
53
+
54
+Docker Demo
55
+-------------------------
56
+It's supposed to be pretty easy to take your Docker to your favourite cloud service, here's a demo of what's our Dockerized bolierplate is like: [https://docker-deployment-yudfxfiaja.now.sh/api](https://docker-deployment-yudfxfiaja.now.sh/api)
57
+
58
+License
59
+-------
60
+
61
+MIT

+ 56
- 0
package.json View File

@@ -0,0 +1,56 @@
1
+{
2
+  "name": "cloudviewer",
3
+  "version": "0.3.0",
4
+  "description": "Starter project for an ES6 RESTful Express API",
5
+  "main": "dist",
6
+  "scripts": {
7
+    "dev": "nodemon -w src --exec \"babel-node src --presets es2015,stage-0\"",
8
+    "dev-api": "babel-node src --presets es2015,stage-0",
9
+    "build": "babel src -s -D -d dist --presets es2015,stage-0",
10
+    "start": "node dist",
11
+    "prestart": "npm run -s build",
12
+    "eslint": "eslint src"
13
+  },
14
+  "eslintConfig": {
15
+    "extends": "eslint:recommended",
16
+    "parserOptions": {
17
+      "ecmaVersion": 7,
18
+      "sourceType": "module"
19
+    },
20
+    "env": {
21
+      "node": true
22
+    },
23
+    "rules": {
24
+      "no-console": 0,
25
+      "no-unused-vars": 1
26
+    }
27
+  },
28
+  "repository": {
29
+    "type": "git",
30
+    "url": "git+https://github.com/developit/express-es6-rest-api.git"
31
+  },
32
+  "author": "Jason Miller <jason@developit.ca>",
33
+  "license": "MIT",
34
+  "dependencies": {
35
+    "body-parser": "^1.13.3",
36
+    "compression": "^1.5.2",
37
+    "config-js": "^1.1.9",
38
+    "cors": "^2.7.1",
39
+    "express": "^4.13.3",
40
+    "morgan": "^1.8.0",
41
+    "resource-router-middleware": "^0.6.0",
42
+    "s3": "^4.4.0"
43
+  },
44
+  "devDependencies": {
45
+    "babel-cli": "^6.9.0",
46
+    "babel-core": "^6.9.0",
47
+    "babel-preset-es2015": "^6.9.0",
48
+    "babel-preset-stage-0": "^6.5.0",
49
+    "eslint": "^3.1.1",
50
+    "nodemon": "^1.9.2"
51
+  },
52
+  "bugs": {
53
+    "url": "https://github.com/developit/express-es6-rest-api/issues"
54
+  },
55
+  "homepage": "https://github.com/developit/express-es6-rest-api#readme"
56
+}

+ 64
- 0
src/api/index.js View File

@@ -0,0 +1,64 @@
1
+import { version } from '../../package.json';
2
+import { Router } from 'express';
3
+import s3 from 's3';
4
+
5
+export default ({ config, db }) => {
6
+	let api = Router();
7
+	api.get('/', (req, res) => {res.json({ version });});
8
+	api.post('/', (req, res) => {
9
+		let last_data = null;
10
+		let content = [];
11
+
12
+		var client = s3.createClient({
13
+		  s3Options: {
14
+			accessKeyId: config.get('s3.accessKeyId'),
15
+			secretAccessKey: config.get('s3.secretAccessKey'),
16
+			region: config.get('s3.region'),
17
+			endpoint: config.get('s3.endpoint')
18
+		  }
19
+		});
20
+
21
+		let bucket = req.body.bucket.split('/')[0];
22
+		let prefix = req.body.bucket.split('/').slice(1, 100).join('/');
23
+		prefix = (prefix.endsWith("/")) ? prefix : prefix + "/";
24
+
25
+		let lo = client.listObjects({
26
+			s3Params: {
27
+				Bucket: bucket,
28
+				Delimiter: '/',
29
+				Prefix: prefix
30
+			},
31
+			recursive: false
32
+		});
33
+
34
+		lo.on('data', function(data) {
35
+			last_data = data;
36
+			for (var d of data.Contents) {
37
+				content.push({
38
+					key: d.Key,
39
+					name: d.Key.split('/').slice(-1)[0],
40
+					url: "http://" + bucket + ".S3.wasabisys.com/" + d.Key
41
+				});
42
+			}
43
+		});
44
+
45
+		lo.on('error', function(err) {
46
+			res.status(400);
47
+			res.send(err.message);
48
+		});
49
+
50
+		lo.on('end', function () {
51
+			let folders = [];
52
+			for (var f of last_data.CommonPrefixes) {
53
+				folders.push(f.Prefix.split('/').slice(-2)[0]);
54
+			}
55
+			res.json({
56
+				content: content,
57
+				folders: folders,
58
+				path: "/" + prefix,
59
+				bucket: bucket
60
+			});
61
+		});
62
+	});
63
+	return api;
64
+};

+ 4
- 0
src/db.js View File

@@ -0,0 +1,4 @@
1
+export default (config, callback) => {
2
+	// connect to a database if needed, then pass it to `callback`:
3
+	callback();
4
+};

+ 37
- 0
src/index.js View File

@@ -0,0 +1,37 @@
1
+import http from 'http';
2
+import express from 'express';
3
+import cors from 'cors';
4
+import morgan from 'morgan';
5
+import bodyParser from 'body-parser';
6
+import initializeDb from './db';
7
+import middleware from './middleware';
8
+import api from './api';
9
+import * as utils from './lib/util.js';
10
+import Config from 'config-js';
11
+import { ApplicationManager } from './managers/appmanager';
12
+
13
+let config_file = utils.config_file_path();
14
+let config = new Config(config_file);
15
+
16
+let app = express();
17
+app.server = http.createServer(app);
18
+app.use(morgan('dev'));
19
+app.use(cors({
20
+	exposedHeaders: config.get('express.corsHeaders')
21
+}));
22
+
23
+app.use(bodyParser.json({
24
+	limit: config.get('express.bodyLimit')
25
+}));
26
+
27
+initializeDb(config, db => {
28
+	// On the next lines it should use appmanager, no config or db
29
+	let appmanager = new ApplicationManager(config, db);
30
+	app.use(middleware({ config, db }));
31
+	app.use('/api', api({ config, db }));
32
+	app.server.listen(process.env.PORT || config.get('express.port', 8080), () => {
33
+		console.log(`Started on port ${app.server.address().port}`);
34
+	});
35
+});
36
+
37
+export default app;

+ 43
- 0
src/lib/util.js View File

@@ -0,0 +1,43 @@
1
+
2
+/**	Creates a callback that proxies node callback style arguments to an Express Response object.
3
+ *	@param {express.Response} res	Express HTTP Response
4
+ *	@param {number} [status=200]	Status code to send on success
5
+ *
6
+ *	@example
7
+ *		list(req, res) {
8
+ *			collection.find({}, toRes(res));
9
+ *		}
10
+ */
11
+export function toRes(res, status=200) {
12
+	return (err, thing) => {
13
+		if (err) return res.status(500).send(err);
14
+
15
+		if (thing && typeof thing.toObject==='function') {
16
+			thing = thing.toObject();
17
+		}
18
+		res.status(status).json(thing);
19
+	};
20
+}
21
+
22
+export function config_file_path() {
23
+	var config_value = process.env.CLOUDVIEWER_CONFIG;
24
+    if (config_value != undefined)
25
+		return config_value;
26
+
27
+    var path = require('path');
28
+    return path.join(__dirname, '../../config/config.js');
29
+}
30
+
31
+export function detectExit (appmanager) {
32
+	// The program will not close instantly
33
+	process.stdin.resume();
34
+	process.on('exit', appmanager.onExitApp.bind(appmanager, {type: 'PROCESS.EXIT'}));
35
+	process.on('SIGINT', appmanager.onExitApp.bind(appmanager, {type: 'CTRL+C'}));
36
+	process.on('uncaughtException', function (err) {
37
+		console.log(err);
38
+		appmanager.onExitApp.bind(appmanager, {
39
+			type: 'EXCEPTION',
40
+			err: err
41
+		});
42
+	});
43
+}

+ 22
- 0
src/managers/appmanager.js View File

@@ -0,0 +1,22 @@
1
+class ApplicationManager {
2
+    constructor(config) {
3
+        this.exiting = false;
4
+    }
5
+
6
+    onExitApp(options) {
7
+        if (this.exiting) {
8
+            return;
9
+        }
10
+        this.exiting = true;
11
+
12
+        if (options.type === 'EXCEPTION') {
13
+            console.error(options.err);
14
+        }
15
+
16
+        setTimeout(function () {
17
+            process.exit(0);
18
+        }, 1000);
19
+    }
20
+}
21
+
22
+export { ApplicationManager };

+ 9
- 0
src/middleware/index.js View File

@@ -0,0 +1,9 @@
1
+import { Router } from 'express';
2
+
3
+export default ({ config, db }) => {
4
+	let routes = Router();
5
+
6
+	// add middleware here
7
+
8
+	return routes;
9
+};

Loading…
Cancel
Save