Skip to content

Commit

Permalink
Merge pull request #293 from akhilesh26/api2
Browse files Browse the repository at this point in the history
feat: Lookup requests for BB API
  • Loading branch information
MonkeyDo committed Aug 1, 2019
2 parents 98f6484 + 95edee5 commit 07fd0f6
Show file tree
Hide file tree
Showing 39 changed files with 4,116 additions and 445 deletions.
1,156 changes: 913 additions & 243 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
"mkdirs": "mkdir -p config static/js/editor static/js/entity static/stylesheets",
"clean": "./scripts/clean.sh",
"prepublishOnly": "npm run clean && npm run mkdirs && npm run copy-client-scripts",
"postinstall": "npm dedup && npm run prepublishOnly",
"build-server-js": "babel src --out-dir lib",
"postinstall": "npm run prepublishOnly",
"build-server-js": "babel src --out-dir lib --ignore src/api",
"build-api-js": "babel src --out-dir lib --ignore 'src/server','src/client'",
"build-client-js": "./scripts/build-client-js.sh",
"build-less": "./scripts/build-less.sh",
"build": "npm run build-less && npm run build-client-js && npm run build-server-js",
"WIP-build-client-webpack": "cross-env NODE_ENV=production SSR=true webpack --progress --config webpack.client.js",
"prestart": "npm run build-less & npm run build-client-js & npm run build-server-js",
"start": "cross-env SSR=true node ./lib/server/app.js",
"start-api": "npm run build-api-js && node ./lib/api/app.js",
"debug": "cross-env DEBUG=bbsite NODE_ENV=development SSR=true babel-node src/server/app.js",
"debug-watch-server": "cross-env DEBUG=bbsite NODE_ENV=development SSR=true nodemon src/server/app.js --watch src/server --exec babel-node",
"lint": "eslint .",
Expand Down Expand Up @@ -83,8 +85,7 @@
"superagent": "^3.8.2",
"superagent-bluebird-promise": "^4.1.0",
"uglify-js": "^3.4.9",
"validator": "^9.1.2",
"webpack-hot-middleware": "^2.22.3"
"validator": "^9.1.2"
},
"devDependencies": {
"babel-cli": "^6.18.0",
Expand All @@ -105,6 +106,7 @@
"bootstrap": "^3.4.1",
"chai": "^4.0.2",
"chai-as-promised": "^7.0.0",
"chai-http": "^4.3.0",
"clean-webpack-plugin": "^0.1.19",
"cross-env": "^5.1.1",
"css-loader": "^1.0.0",
Expand All @@ -115,6 +117,7 @@
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-react": "^7.5.1",
"factor-bundle": "^2.3.3",
"faker": "^4.1.0",
"file-loader": "^2.0.0",
"flow-bin": "^0.69.0",
"husky": "^0.14.3",
Expand All @@ -132,11 +135,14 @@
"rewire": "^3.0.2",
"style-loader": "^0.21.0",
"supertest": "^3.0.0",
"swagger-jsdoc": "^3.2.9",
"swagger-ui-express": "^4.0.7",
"uuid": "^3.3.2",
"webpack": "^4.16.4",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.1.0",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.3",
"webpack-node-externals": "^1.7.2",
"write-assets-webpack-plugin": "^1.0.4"
}
Expand Down
131 changes: 131 additions & 0 deletions src/api/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright (C) 2014-2015 Ben Ockmore
* 2015-2017 Sean Burke
* 2015 Leo Verto
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* eslint global-require: 'warn' */


import BookBrainzData from 'bookbrainz-data';
import Debug from 'debug';
import Promise from 'bluebird';
import {get as _get} from 'lodash';
import {allowOnlyGetMethod} from './helpers/utils';
import appCleanup from '../common/helpers/appCleanup';
import bodyParser from 'body-parser';
import compression from 'compression';
import config from '../common/helpers/config';
import express from 'express';
import logger from 'morgan';
import path from 'path';
import redis from 'connect-redis';
import routes from './routes';
import session from 'express-session';
import swaggerRoute from './swagger';


Promise.config({
longStackTraces: true,
warnings: true
});

// Initialize application
const app = express();
app.locals.orm = BookBrainzData(config.database);


app.set('trust proxy', config.site.proxyTrust);

if (app.get('env') !== 'testing') {
app.use(logger('dev'));
}

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(compression());


const RedisStore = redis(session);
app.use(session({
cookie: {
maxAge: _get(config, 'session.maxAge', 2592000000),
secure: _get(config, 'session.secure', false)
},
resave: false,
saveUninitialized: false,
secret: config.session.secret,
store: new RedisStore({
host: _get(config, 'session.redis.host', 'localhost'),
port: _get(config, 'session.redis.port', 6379)
})
}));


// Set up routes
routes(app);

// use swagger-Ui-express for your app documentation endpoint
app.use('/api-docs', swaggerRoute);

// Allow only get requests for now throw error for any other type of requests
app.all('/*', allowOnlyGetMethod);

// Catch 404 and forward to error handler
app.use((req, res, next) => {
res.status(404).send({message: `Incorrect endpoint ${req.path}`});
});


const debug = Debug('bbapi');

const DEFAULT_API_PORT = 9098;
app.set('port', process.env.PORT || DEFAULT_API_PORT); // eslint-disable-line no-process-env,max-len

const server = app.listen(app.get('port'), () => {
debug(`Express server listening on port ${server.address().port}`);
});

/* eslint-disable no-console */
function cleanupFunction() {
return new Promise((resolve, reject) => {
console.log('Cleaning up before closing');
server.close((err) => {
if (err) {
console.log('Error while closing server connections');
reject(err);
}
else {
console.log('Closed all server connections. Bye bye!');
resolve();
}
});
// force-kill after X milliseconds.
if (config.site.forceExitAfterMs) {
setTimeout(() => {
reject(new Error(`Cleanup function timed out after ${config.site.forceExitAfterMs} ms`));
}, config.site.forceExitAfterMs);
}
});
}
/* eslint-enable no-console */

// Run cleanup function
appCleanup(cleanupFunction);

export default server;
61 changes: 61 additions & 0 deletions src/api/helpers/entityLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2019 Akhilesh Kumar
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

// @flow


import * as commonUtils from '../../common/helpers/utils';

/**
* This is a middleware function to load entity detail according to given relations
*
* @param {string} modelName - Name of entity model
* @param {string[]} relations - List of entity relations for fetching the related detail
* @param {string} errMessage - Error message, if any error will occur
* @returns {object} an object containing the error message if any error will occur.
* If entity is found succesfully in the database this function set the entity data
* at res.locals.entity and return to next function.
* @example
* const errorMessage = 'Edition not found'';
* makeEntityLoader('Edition', ['defaultAlias.language', 'editionStatus'], errMessage);
*
* @description
* First, check the BBID is valid or not.
* If BBID is valid then extract the entity data from database by using BBID and relations of
* that entity. If entity is found succesfully then set that entity data to the res.locals.entity
* otherwise return an object {message: errMessage} as response with status code 404.
* If the BBID is not valid then return a status code 406 and an object {message: 'BBID is not valid uuid'}.
*/


export function makeEntityLoader(modelName, relations, errMessage) {
return async (req, res, next) => {
const {orm} = req.app.locals;
if (commonUtils.isValidBBID(req.params.bbid)) {
try {
const entityData = await orm.func.entity.getEntity(orm, modelName, req.params.bbid, relations);
res.locals.entity = entityData;
return next();
}
catch (err) {
return res.status(404).send({message: errMessage});
}
}
return res.status(406).send({message: 'BBID is not valid uuid'});
};
}

0 comments on commit 07fd0f6

Please sign in to comment.