Skip to content

Commit 8cb5c63

Browse files
Initial commit
0 parents  commit 8cb5c63

25 files changed

+6371
-0
lines changed

.eslintrc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"extends": "airbnb-base",
3+
"rules": {
4+
"no-use-before-define": 0,
5+
"strict": 0,
6+
"comma-dangle": [2, "never"],
7+
"func-names": 0,
8+
"no-underscore-dangle": 0,
9+
"prefer-rest-params": 0,
10+
"no-param-reassign": 0,
11+
"prefer-template": 0,
12+
"new-cap": 0,
13+
"global-require": 0,
14+
"consistent-return": 0,
15+
"max-len": [2, 200],
16+
"camelcase": 0,
17+
"no-console": "off"
18+
},
19+
"parserOptions": {
20+
"ecmaVersion": 6
21+
},
22+
"globals": {
23+
"describe": true,
24+
"it": true,
25+
"before": true,
26+
"beforeEach": true,
27+
"after": true,
28+
"afterEach": true
29+
}
30+
}

.gitignore

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
node_modules
2+
*.zip
3+
# Logs
4+
logs
5+
*.log
6+
npm-debug.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+
# node-waf configuration
27+
.lock-wscript
28+
29+
# Compiled binary addons (http://nodejs.org/api/addons.html)
30+
build/Release
31+
32+
# Dependency directories
33+
node_modules
34+
jspm_packages
35+
36+
# Optional npm cache directory
37+
.npm
38+
39+
# Optional eslint cache
40+
.eslintcache
41+
42+
# Optional REPL history
43+
.node_repl_history

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM node:10.16.3-alpine
2+
RUN mkdir -p /usr/src/app
3+
WORKDIR /usr/src/app
4+
COPY package*.json ./
5+
RUN npm install
6+
COPY . .
7+
EXPOSE 3000
8+
CMD [ "node", "app.js" ]

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node app.js

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Starter pack for NodeJs API
2+
3+
## Dependencies
4+
5+
- runs on node.js v10.16.3
6+
- [express 4+](http://expressjs.com/)
7+
- [eslint](http://eslint.org/)
8+
- [PostGre] - docker image of postgre
9+
- [POSTMAN](https://www.getpostman.com) chrome extension for verification
10+
11+
## Configuration
12+
13+
- Edit configuration in `config/default.json` and
14+
- custom environment variables names in `config/custom-environment-variables.json`,
15+
- Db configuration in config.json
16+
Following variables can be configured:
17+
18+
- `port` the port to listen
19+
- `logLevel` the log level `debug` or `info`
20+
- `version` the version of api
21+
- `config.json use for db onfiguration`
22+
23+
## Local Deployment
24+
25+
- Please make sure to configure url of database rightly in `config/config.json` or use **host:0.0.0.0**.
26+
- mongo docker instance run : cd docker/postgre ->run docker-compose up
27+
- Install dependencies `npm i`
28+
- run lint check `npm run lint`
29+
- Start app `npm start`
30+
31+
## Docker Deployment
32+
33+
- Please make sure to configure url of database rightly in `config/config.json` or use host **host:db**.
34+
- docker ps -a //to check already postgres instance is running
35+
- docker stop containerid
36+
- docker rm containerid
37+
- docker-compose build --no-cache
38+
- docker-compose up
39+
40+
## Verification
41+
42+
- Load postman collection:
43+
- endpoints: docs/api.postman_collection.json
44+
- environment: docs/api.postman_environment.json
45+
- use Authorization header Bearer {{user_token}}

app-routes.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
/*
4+
* Copyright (c) 2016 TopCoder, Inc. All rights reserved.
5+
*/
6+
7+
/**
8+
* This configuration of passport for express App.
9+
*/
10+
const _ = require('lodash');
11+
const glob = require('glob');
12+
const Path = require('path');
13+
const config = require('config');
14+
const helper = require('./common/helper');
15+
/**
16+
* Configure routes for express
17+
* @param app the express app
18+
*/
19+
module.exports = (app) => {
20+
// load all routes.js in modules folder.
21+
glob.sync(Path.join(__dirname, './modules/**/routes.js')).forEach((routes) => {
22+
/* Load all routes */
23+
_.each(
24+
require(Path.resolve(routes)), // eslint-disable-line import/no-dynamic-require
25+
(verbs, path) => {
26+
_.each(verbs, (def, verb) => {
27+
const controllerPath = Path.join(
28+
Path.dirname(routes),
29+
`./controllers/${def.controller}`
30+
);
31+
const method = require(controllerPath)[def.method]; // eslint-disable-line import/no-dynamic-require
32+
if (!method) {
33+
throw new Error(`${def.method} is undefined`);
34+
}
35+
const actions = [];
36+
actions.push((req, res, next) => {
37+
req.signature = `${def.controller}#${def.method}`;
38+
next();
39+
});
40+
actions.push(method);
41+
app[verb](
42+
`/api/${config.version}${path}`,
43+
helper.autoWrapExpress(actions)
44+
);
45+
});
46+
}
47+
);
48+
});
49+
};

app.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict';
2+
3+
/*
4+
* Copyright (c) 2016 TopCoder, Inc. All rights reserved.
5+
*/
6+
/**
7+
* Contains express application configurations.
8+
*/
9+
if (!process.env.NODE_ENV) {
10+
process.env.NODE_ENV = 'development';
11+
}
12+
13+
const cors = require('cors');
14+
const config = require('config');
15+
const express = require('express');
16+
17+
const app = express();
18+
const morgan = require('morgan');
19+
const bodyParser = require('body-parser');
20+
const _ = require('lodash');
21+
const logger = require('./common/logger');
22+
23+
const { port } = config;
24+
25+
app.use(cors());
26+
app.use(bodyParser.json());
27+
app.use(bodyParser.urlencoded({ extended: true }));
28+
app.use(morgan('dev'));
29+
30+
require('./app-routes')(app);
31+
32+
// The error handler,log error and return 500 error
33+
// eslint-disable-next-line no-unused-vars
34+
app.use((err, req, res, next) => {
35+
logger.logFullError(err, req.signature || `${req.method} ${req.url}`);
36+
const errorResponse = {};
37+
const status = err.isJoi ? 400 : err.httpStatus || 500;
38+
39+
if (_.isArray(err.details)) {
40+
errorResponse.fields = _.map(err.details, 'path').join(', ');
41+
if (err.isJoi) {
42+
_.map(err.details, (e) => {
43+
if (e.message) {
44+
if (_.isUndefined(errorResponse.message)) {
45+
errorResponse.message = e.message;
46+
} else {
47+
errorResponse.message += ', ' + e.message;
48+
}
49+
}
50+
});
51+
}
52+
}
53+
if (_.isUndefined(errorResponse.message)) {
54+
if (err.message) {
55+
errorResponse.message = err.message;
56+
} else {
57+
errorResponse.message = 'server error';
58+
}
59+
}
60+
61+
errorResponse.code = status;
62+
res.status(status).json(errorResponse);
63+
});
64+
65+
app.listen(port, '0.0.0.0');
66+
logger.info(
67+
'Express server listening on port %d in %s mode',
68+
port,
69+
process.env.NODE_ENV
70+
);
71+
72+
module.exports = app;

common/errors.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
/*
4+
* Copyright (c) 2016 TopCoder, Inc. All rights reserved.
5+
*/
6+
7+
/**
8+
* This file defines application errors.
9+
*/
10+
11+
const util = require('util');
12+
13+
/**
14+
* Helper function to create generic error object with http status code
15+
* @param {String} name the error name
16+
* @param {Number} statusCode the http status code
17+
* @returns {Function} the error constructor
18+
* @private
19+
*/
20+
function _createError(name, statusCode) {
21+
/**
22+
* The error constructor
23+
* @param {String} message the error message
24+
* @param {String} [cause] the error cause
25+
* @constructor
26+
*/
27+
function ErrorCtor(message, cause) {
28+
Error.call(this);
29+
Error.captureStackTrace(this);
30+
this.message = message || name;
31+
this.cause = cause;
32+
this.httpStatus = statusCode;
33+
}
34+
35+
util.inherits(ErrorCtor, Error);
36+
ErrorCtor.prototype.name = name;
37+
return ErrorCtor;
38+
}
39+
40+
module.exports = {
41+
ValidationError: _createError('ValidationError', 400),
42+
BadRequestError: _createError('BadRequestError', 400),
43+
NotFoundError: _createError('NotFoundError', 404),
44+
ForbiddenError: _createError('ForbiddenError', 403),
45+
UnauthorizedError: _createError('UnauthorizedError', 401),
46+
InternalserverError: _createError('InternalserverError', 500)
47+
};

common/helper.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
/*
4+
* Copyright (c) 2016 TopCoder, Inc. All rights reserved.
5+
*/
6+
7+
/**
8+
* This file defines helper methods
9+
*/
10+
const _ = require('lodash');
11+
const co = require('co');
12+
13+
14+
/**
15+
* Wrap generator function to standard express function
16+
* @param {Function} fn the generator function
17+
* @returns {Function} the wrapped function
18+
*/
19+
function wrapExpress(fn) {
20+
return function wrapGenerator(req, res, next) {
21+
co(fn(req, res, next)).catch(next);
22+
};
23+
}
24+
25+
/**
26+
* Wrap all generators from object
27+
* @param obj the object (controller exports)
28+
* @returns {Object|Array} the wrapped object
29+
*/
30+
function autoWrapExpress(obj) {
31+
if (_.isArray(obj)) {
32+
return obj.map(autoWrapExpress);
33+
}
34+
if (_.isFunction(obj)) {
35+
if (obj.constructor.name === 'GeneratorFunction') {
36+
return wrapExpress(obj);
37+
}
38+
return obj;
39+
}
40+
_.each(obj, (value, key) => {
41+
obj[key] = autoWrapExpress(value);
42+
});
43+
return obj;
44+
}
45+
46+
module.exports = {
47+
wrapExpress,
48+
autoWrapExpress
49+
};

0 commit comments

Comments
 (0)