aboutsummaryrefslogtreecommitdiffstats
path: root/server.js
diff options
context:
space:
mode:
Diffstat (limited to 'server.js')
-rw-r--r--server.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..e347e37
--- /dev/null
+++ b/server.js
@@ -0,0 +1,205 @@
+const express = require('express');
+const bodyParser = require('body-parser');
+const cors = require('cors')
+const crypto = require('crypto');
+const pkg = require('./package.json');
+
+// App constants
+const port = process.env.PORT || 5000;
+const apiPrefix = '/api';
+
+// Store data in-memory, not suited for production use!
+const db = {
+ test: {
+ user: 'test',
+ currency: '$',
+ description: `Test account`,
+ balance: 75,
+ transactions: [
+ { id: '1', date: '2020-10-01', object: 'Pocket money', amount: 50 },
+ { id: '2', date: '2020-10-03', object: 'Book', amount: -10 },
+ { id: '3', date: '2020-10-04', object: 'Sandwich', amount: -5 }
+ ],
+ }
+};
+
+// Create the Express app & setup middlewares
+const app = express();
+app.use(bodyParser.urlencoded({ extended: true }));
+app.use(bodyParser.json());
+app.use(cors({
+ origin: /http:\/\/(127(\.\d){3}|localhost)/,
+ optionsSuccessStatus: 200
+}));
+app.options('*', cors());
+
+// ***************************************************************************
+
+// Configure routes
+const router = express.Router();
+
+// Get server infos
+router.get('/', (req, res) => {
+ return res.send(`${pkg.description} v${pkg.version}`);
+});
+
+// ----------------------------------------------
+
+// Create an account
+router.post('/accounts', (req, res) => {
+ // Check mandatory request parameters
+ if (!req.body.user || !req.body.currency) {
+ return res.status(400).json({ error: 'Missing parameters' });
+ }
+
+ // Check if account already exists
+ if (db[req.body.user]) {
+ return res.status(409).json({ error: 'User already exists' });
+ }
+
+ // Convert balance to number if needed
+ let balance = req.body.balance;
+ if (balance && typeof balance !== 'number') {
+ balance = parseFloat(balance);
+ if (isNaN(balance)) {
+ return res.status(400).json({ error: 'Balance must be a number' });
+ }
+ }
+
+ // Create account
+ const account = {
+ user: req.body.user,
+ currency: req.body.currency,
+ description: req.body.description || `${req.body.user}'s budget`,
+ balance: balance || 0,
+ transactions: [],
+ };
+ db[req.body.user] = account;
+
+ return res.status(201).json(account);
+});
+
+// ----------------------------------------------
+
+// Get all data for the specified account
+router.get('/accounts/:user', (req, res) => {
+ const account = db[req.params.user];
+ // Check if account exists
+ if (!account) {
+ return res.status(404).json({ error: 'User does not exist' });
+ }
+
+ return res.json(account);
+});
+
+// ----------------------------------------------
+
+// Remove specified account
+router.delete('/accounts/:user', (req, res) => {
+ const account = db[req.params.user];
+
+ // Check if account exists
+ if (!account) {
+ return res.status(404).json({ error: 'User does not exist' });
+ }
+
+ // Removed account
+ delete db[req.params.user];
+
+ res.sendStatus(204);
+});
+
+// ----------------------------------------------
+
+// Add a transaction to a specific account
+router.post('/accounts/:user/transactions', (req, res) => {
+ const account = db[req.params.user];
+
+ // Check if account exists
+ if (!account) {
+ return res.status(404).json({ error: 'User does not exist' });
+ }
+
+ // Check mandatory requests parameters
+ if (!req.body.date || !req.body.object || !req.body.amount) {
+ return res.status(400).json({ error: 'Missing parameters' });
+ }
+
+ // Convert amount to number if needed
+ let amount = req.body.amount;
+ if (amount && typeof amount !== 'number') {
+ amount = parseFloat(amount);
+ }
+
+ // Check that amount is a valid number
+ if (amount && isNaN(amount)) {
+ return res.status(400).json({ error: 'Amount must be a number' });
+ }
+
+ // Generates an ID for the transaction
+ const id = crypto
+ .createHash('md5')
+ .update(req.body.date + req.body.object + req.body.amount)
+ .digest('hex');
+
+ // Check that transaction does not already exist
+ if (account.transactions.some((transaction) => transaction.id === id)) {
+ return res.status(409).json({ error: 'Transaction already exists' });
+ }
+
+ // Add transaction
+ const transaction = {
+ id,
+ date: req.body.date,
+ object: req.body.object,
+ amount,
+ };
+ account.transactions.push(transaction);
+
+ // Update balance
+ account.balance += transaction.amount;
+
+ return res.status(201).json(transaction);
+});
+
+// ----------------------------------------------
+
+// Remove specified transaction from account
+router.delete('/accounts/:user/transactions/:id', (req, res) => {
+ const account = db[req.params.user];
+
+ // Check if account exists
+ if (!account) {
+ return res.status(404).json({ error: 'User does not exist' });
+ }
+
+ const transactionIndex = account.transactions.findIndex(
+ (transaction) => transaction.id === req.params.id
+ );
+
+ // Check if transaction exists
+ if (transactionIndex === -1) {
+ return res.status(404).json({ error: 'Transaction does not exist' });
+ }
+
+ // Remove transaction
+ account.transactions.splice(transactionIndex, 1);
+
+ res.sendStatus(204);
+});
+
+// ***************************************************************************
+
+// set custom header
+app.use((req, res, next) => {
+ res.append('tsec', 'fxrAJnJLVzgp9PFMJKmmRLVHVscfyw3Mjdr');
+ next();
+})
+
+// Add 'api` prefix to all routes
+app.use(apiPrefix, router);
+
+// Start the server
+app.listen(port, () => {
+ console.log(`Server listening on port ${port}`);
+});