skip to Main Content

I’m trying to use PayPal API REST from NodeJS, so i have to make async calls with Axios, but i’m doing this on separarted classes, i have two classes:

const axios = require("axios");

/**PayPal main class, this class will setup PayPal credentials when instance */
class PayPal {

   constructor() {
        return new Promise(async (resolve, reject) => {
            await this.setupEnvironment();
            resolve();
        });
    }

    setupEnvironment = async () => {
        
        // Sets base URL to send requests
        this.setAPIDomain();

        // Sets PayPal endpoints
        this.setPayPalEndpoints();

        // Sets API Keys
        await this.setAPIKeys();

    }

    setAPIKeys = async () => {

        const paypal_credentials = this.getPayPalCredetials();
        const { client_id, client_secret } = paypal_credentials;

        try {

            const response = await axios({
                method: "post",
                url: this.endpoints.get_access_token,
                data: "grant_type=client_credentials",
                headers: {
                  "Accept-Language": "en_US",
                  "Accept": "application/json"
                },
                auth: {
                    username: client_id,
                    password: client_secret
                },
            });

            this.access_token = response.data.access_token;
            
        } catch (error) {
            console.log(error.response.data);
            throw new Error(error.response.data.error_description);
        }


    }

}

class Customer extends PayPal() {

    constructor() {
        super();
        // Customer class do some others actions
    }

}


$paypal_gateway = new Customer();

As you can see, in the PayPal class is a method (setAPIKeys) who sends a request to PayPal to generate mi access token, if i put a console.log(this.access_token) i’m getting my access token, but it only happens if i put it inside the setAPIKeys method (I’m omiting some methods of this class here).

If i put console.log($paypal_gateway.access_token) i’m getting undefined, and that’s obvious ’cause the PayPal class constructor is returning a promise, but in the Customer class constructor i’m just calling the super() method without an async way, i tried to put "async" on the left of super() but it doesn’t works, i also tried this:

class Customer extends PayPal {

    constructor() {

        return new Promise(async (resolve, reject) => {
            // Call to parent constructor
            super();

            // Set Customer properties
            this.setCustomer();
            resolve();
        });

    }

}

But also doesn’t works, if i put a console.log(this.access_token) under the super() function i’m also getting undefined, so i don’t know what can i do to await this super() constructor, can you help me please?

2

Answers


  1. Chosen as BEST ANSWER

    I solve it with help of @sdgluck comment, i avoid the constructor method and implements an async init method:

    const axios = require("axios");
    
    /**PayPal main class, this class will setup PayPal credentials when instance */
    class PayPal {
    
        setupEnvironment = async () => {
            
            // Sets base URL to send requests
            this.setAPIDomain();
    
            // Sets PayPal endpoints
            this.setPayPalEndpoints();
    
            // Sets API Keys
            await this.setAPIKeys();
    
        }
    
        setAPIKeys = async () => {
    
            const paypal_credentials = this.getPayPalCredetials();
            const { client_id, client_secret } = paypal_credentials;
    
            try {
    
                const response = await axios({
                    method: "post",
                    url: this.endpoints.get_access_token,
                    data: "grant_type=client_credentials",
                    headers: {
                      "Accept-Language": "en_US",
                      "Accept": "application/json"
                    },
                    auth: {
                        username: client_id,
                        password: client_secret
                    },
                });
    
                this.access_token = response.data.access_token;
                
            } catch (error) {
                console.log(error.response.data);
                throw new Error(error.response.data.error_description);
            }
    
    
        }
    
    }
    
    class Customer extends PayPal() {
    
        async init = () => {
            await this.setupEnvironment();
            // More init code
        }
    
    }
    
    const paypal_gateway = new Customer();
    await paypal_gateway.init(); // <- code inside another async function
    
    

    Hope this help to others, thanks a lot!


  2. The constructor must return an object — specifically an instance of the class it’s defined in. It cannot return a Promise, which is what an async function does. You will have to implement a setup step. You could make an async factory function which instantiates the object and performs all setup steps, and returns the resulting object.

    async function createPaypal {
      const paypal = new PayPal()
      await paypal.setupEnvironment()
      return paypal;
    

    }

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search