1
\$\begingroup\$

The task I'm doing is, fetch external API, then save the results to database.

I'm a beginner, I really wanna improve my code, to handle error well, and remove redundant code. The code is working, but I'm bit confused with promise and try-catch. I watched some tutorial, still not sure in the situation which way is better. Anyone could please help me? I really appreciate it!

//app.js
const express = require('express')
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args))
const app = express()
const sqlite3 = require('sqlite3').verbose()
const ExternalAPI = 'https://open.er-api.com/v6/latest'

const db = new sqlite3.Database('currency.db');

const connectDatabase = () => {
    return new Promise((resolve, reject) => {
        db.on('error', (err) => {
            reject(new Error(`Failed to connect to database: ${err.message}`));
        });
        db.on('open', () => {
            console.log('Connected to the currency database.');
            resolve(db);
        });
    });
};

const createTable = (db) => {
    return new Promise((resolve, reject) => {
        db.run(
            `CREATE TABLE IF NOT EXISTS results (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          request_at TEXT NOT NULL,
          rate_USD REAL NOT NULL,
          rate_EUR REAL NOT NULL,
          rate_GBP REAL NOT NULL,
          rate_CNY REAL NOT NULL
        )`,
            (err) => {
                if (err) reject(new Error(`Failed to create table: ${err.message}`))
                else resolve();
            }
        );
    });
};

const connectDatabaseAndTable = async () => {
    try {
        await connectDatabase();
        await createTable();
    } catch (err) {
        console.error(err);
    }
};



const fetchExchangeRates = async () => {
    try {
        const res = await fetch(ExternalAPI)
        const data = await res.json()
        return data
    } catch (err) {
        console.error(err)
        throw new Error('Failed to fetch exchange rates')
    }
}

const insertExchangeRatesAndTimeIntoDB = async (db, rates) => {
    const requestAt = new Date().toLocaleString()
    const { USD, EUR, GBP, CNY } = rates
    const query = `INSERT INTO results(request_at, rate_USD, rate_EUR, rate_GBP, rate_CNY) VALUES (?,?,?,?,?)`
    const params = [requestAt, USD, EUR, GBP, CNY]
    try {
        return new Promise((resolve, reject) => {
            db.run(query, params, (err) => {
                if (err) reject(err)
                else resolve()
            })
        })
    } catch (err) {
        console.error(err)
        throw new Error('Failed to insert exchange rates into the database')
    }
}

const retrieveExchangeRatesFromDB = async (db) => {
    try {
        db.all(`SELECT * FROM results`, [], (err, rows) => {
            if (err) console.error(err.message);
            rows.map((row) => console.log(row))
        })
    } catch (err) {
        console.error(err)
        throw new Error('Failed to retrieve exchange rates from the database')
    }
}

 const closeDB = (db) => {
     return new Promise((resolve, reject) => {
         db.close((err) => {
             if (err) {
                 console.error(err)
                 reject(err);
             } else resolve()
         })
     })
 }

app.get('/', async (req, res) => {
    try {
        connectDatabaseAndTable()
        const exchangeRates = await fetchExchangeRates()
        await insertExchangeRatesAndTimeIntoDB(db, exchangeRates.rates)
        const retrievedRates = await retrieveExchangeRatesFromDB(db)
        console.log(retrievedRates)
        closeDB(db)
        res.json({ status: 200, success: true })
    } catch (err) {
        console.error(err)
        res.status(500).send('Something went wrong...')
    }
})

module.exports = app 
//index.js
const express = require('express')
const app = require('./app')
const PORT = 5005

app.listen(PORT, () => {
    console.log(`App is listening on http://localhost:${PORT}`)
}) 
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You are using promises conservatively. Example 1: await connectDatabase(); await createTable(); Example 2: await fetch(ExternalAPI) await res.json(); In both cases you resolve promise A and then resolve promise B. There's an opportunity to chain them. Here the difference will be trivial, but it's a good habit to get into. For large tasks we can schedule A on one core, B on another core, and there's some overlap, which reduces elapsed wallclock time. Also, .get() opens / closes DB, but remembering that "it's still open" would reduce latency for repeated GETs. Please COMMIT inserts. \$\endgroup\$
    – J_H
    Feb 15 at 16:42

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.