Search code examples
node.jsfunctionblocking

Blocking Function on NodeJS


I'm building a SDK for an API using NodeJS, which can be found here. My problem is that when the user declare the module, it gives an username and password that I need to validate, and a token that must be used for future calls. So, this token is stored at irecarga.token, and for every future call I'll have to use it in order to identify the user. My problem is that if the user calls another function straight after the declaration, the declaration will probably not finish in time (because it does a HTTP POST) and the attribute token will be null.

// module declaration which requires a HTTP call and updates irecarga.token
var irecarga = require('../')({
    username: process.env.IRECARGA_USERNAME,
    password: process.env.IRECARGA_PASSWORD
})

// function called straight after declaration which uses irecarga.token
irecarga.getServiceProviders(48, function(err, data){
    // this code won't even run because the token = null will break the code
    console.log('err: ', err)
    console.log('data', data)
})

So, I saw plenty of solutions for creating blocking functions with Node, I could use callbacks or other modules that would require to send the functions I want to execute as parameter for other functions.

These solutions would most likely work, but the code will be ugly and messy. Besides, I don't think I'm innovating, actually this is the way I saw big companies like Microsoft and Google to declare their API keys.

Am I missing something here? Is there anything I could add inside of the validation function that would make any method of iRecarga wait until validation is done?


Solution

  • Using await you can add a one-liner to each of your API methods that will wait for the initializatoin (authentication) to complete by waiting for a promise to resolve. Here is one way you can do it. I use latest syntax with babel.

    // myapi.js
    
    import login from './auth';
    import {query, insert} from './db';
    
    let authenticated = null, user = null;
    
    async function getProviders({regionId}) {
      await authenticated;
      return await query({region:regionId});
    }
    
    async function order({provider, service}) {
      await authenticated;
      return await insert({entity:'orders'}, {service, user});
    }
    
    export default function ({username, password}) {
      authenticated = new Promise( async (resolve, reject) => {
        const valid = await login({username, password});
        if (valid) {
          user = username;
          resolve();
        } else {
          reject();
        }
      });
      return {getProviders, order};
    }
    
    // test/myapi.js
    
    import myapi from '../myapi';
    
    async function test() {
      let api = myapi({username:'tom', password:'1234'});
      let providers = await api.getProviders({regionId:48});
      console.log(providers);
      let providers2 = await api.getProviders({regionId:5});
      console.log(providers2);
    }
    
    test().catch(console.error);