UNPKG

@windingtree/wt-write-api

Version:

API to write data to the Winding Tree platform

108 lines (92 loc) 3.6 kB
const express = require('express'); const bodyParser = require('body-parser'); const morgan = require('morgan'); const swaggerUi = require('swagger-ui-express'); const cors = require('cors'); const slash = require('express-slash'); const path = require('path'); const YAML = require('yamljs'); const config = require('./config'); const WT = require('./services/wt'); const { version } = require('../package.json'); const { HttpError, HttpInternalError, Http404Error, HttpBadRequestError } = require('./errors'); const { attachAccount, handleOnChainErrors, handleDataFetchingErrors } = require('./middleware'); const { createHotel, updateHotel, forceUpdateHotel, deleteHotel, getHotel, transferHotel } = require('./controllers/hotels'); const { createAccount, updateAccount, deleteAccount } = require('./controllers/accounts'); const app = express(); // No need to leak information and waste bandwith with this // header. app.disable('x-powered-by'); app.enable('strict routing'); // Swagger docs. const swaggerDocument = YAML.load(path.resolve(__dirname, '../docs/swagger.yaml')); swaggerDocument.servers = [{ url: config.baseUrl }]; swaggerDocument.info.version = version; app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); app.use(cors()); app.use(bodyParser.json()); app.use((err, req, res, next) => { // Catch and handle bodyParser errors. if (err.statusCode === 400 && err.type === 'entity.parse.failed') { return next(new HttpBadRequestError('badRequest', 'Invalid JSON.')); } next(err); }); // Logg HTTP requests. app.use(morgan(':remote-addr :remote-user [:date[clf]] :method :url HTTP/:http-version :status :res[content-length] - :response-time ms', { stream: { write: (msg) => config.logger.info(msg), }, })); // Root handler app.get('/', async (req, res) => { const wt = WT.get(); res.status(200).json({ docs: `${config.baseUrl}/docs/`, info: 'https://github.com/windingtree/wt-write-api/blob/master/README.md', version, config: process.env.WT_CONFIG, ethNetwork: config.ethNetwork, entrypointAddress: config.entrypointAddress, wtDirectoryAddress: await wt.getDirectoryAddress(), wtFactoryAddress: await wt.getFactoryAddress(), dataFormatVersions: config.dataFormatVersions, }); }); // Accounts const router = express.Router({ strict: true, }); // NOTE: For security reasons, accounts are write only. router.post('/accounts', createAccount); router.put('/accounts/:id', attachAccount, updateAccount); router.delete('/accounts/:id', attachAccount, deleteAccount); // Hotels router.post('/hotels', attachAccount, createHotel, handleOnChainErrors); router.get('/hotels/:address', getHotel, handleOnChainErrors); router.delete('/hotels/:address', attachAccount, deleteHotel, handleOnChainErrors); router.patch('/hotels/:address', attachAccount, updateHotel, handleOnChainErrors, handleDataFetchingErrors); router.put('/hotels/:address', attachAccount, forceUpdateHotel, handleOnChainErrors, handleDataFetchingErrors); router.post('/hotels/:address/transfer', attachAccount, transferHotel, handleOnChainErrors); app.use(router); app.use(slash()); // 404 handler app.use('*', (req, res, next) => { next(new Http404Error()); }); // Error handler app.use((err, req, res, next) => { if (!(err instanceof HttpError)) { config.logger.error(err.stack); err = new HttpInternalError(null, err.originalError, err.message); } const response = res.status(err.status); if (err.headers) { response.set(err.headers); } response.json(err.toPlainObject()); }); module.exports = { app, };