0

I must connect to a LDAP server and find user based on a specific ID.

I've decided to use ldapjs module.

I managed to create my client and bind him so I can search for an user with success.

My problem is, as I only use async/await, that I don't understant how to handle error in callbacks... For example with this simple code from ldapjs library :

public static async search(searchOptions: SearchOptions) {
    LdapService.bind()

    LdapService.getClient()?.search('ou=*****,ou=***,dc=****,dc=****', searchOptions, function (err, res) {
      ifError(err)

      res.on('searchEntry', function (entry) {
        // ----------------------
        // an error came from here
        throw new Error('test') 
        // ----------------------

        console.log('entry: ' + JSON.stringify(entry.object));
      });

      res.on('searchReference', function (referral) {
        console.log('referral: ' + referral.uris.join());
      });

      res.on('error', function (err) {
        console.error('error: ' + err.message);
      });

      res.on('end', function (result) {
        console.log('status: ' + result?.status);
      });
    })
  }

LdapService.getClient() is a singleton method that return the result of createClient -> works fine

LdapService.bind() is a method that just bind with the server with correct credentials -> works fine

I just can't manage to handle my error "test"... How am I supposed to handle it?

Is the search method really async?

Can I do it the async/await way? :P

PS: the DN string ("ou=,ou=,dc=,dc=") is hidden due to security reasons and the code works great without throwing an error ;)

2 Answers 2

0

For anyone passing here and struggling with callback like me, here the "fix" I found :

public static async search(searchOptions: SearchOptions) {
    // wrapping the all thing in a Promise that can be in a try/catch -> error will be handled there
    return await new Promise((resolve, reject) => {
      LdapService.getClient()?.search('ou=****,ou=****,dc=****,dc=****', searchOptions, function (err, res) {
        if (err) {
          // handle connection error I guess ?
          reject(err)
        }

        res.on('searchEntry', function (entry) {
          try {
            // -------------
            // Same test as before
            throw new Error('test')
            // -------------

            resolve(JSON.stringify(entry.object))
          } catch (err) {
            // error must be catched to call reject method !
            reject(err)
          }
        });

        res.on('error', function (err) {
          // handle API error when looking for the specific ID I guess ?
          reject(err)
        });
      })
    })
  }

What solved my problem? Wrapping the all thing in a Promise.

All the "res.on" methods before were something like Promise listeners. So the all method search (the one inside mine) was a sort of asynchronous call.

Now I can call resolve/reject methods to return data and error.

Also, I can call my static search method the async/await way.

When you're not familiar with callbacks... ^^"

Sign up to request clarification or add additional context in comments.

1 Comment

I also remove all unused "res.on" methods! Maybe there is a shorter way but this one works ;)
0

There is another way to do this. Since the Client object in ldapjs is en EventEmitter, you can turn on the 'captureRejections' boolean.

details: https://nodejs.org/api/events.html#error-events

Example from docs:

import { EventEmitter } from 'node:events';

EventEmitter.captureRejections = true;
const ee1 = new EventEmitter();
ee1.on('something', async (value) => {
  throw new Error('kaboom');
});

ee1.on('error', console.log);

when building the client, you can pass this as an option, and then the .on handlers behave a lot better. Once you add it to the client, all the bind and search functions use it as well.

async buildLdapClient() {
    return new Promise((resolve, reject) => {

        const options: ClientOptions = {
            url: ldaps://something.here.not.there.com:636,
            connectTimeout: 5000,
            timeout: 5000,
            reconnect: false,
            captureRejections: true
        }

        let client = ldapjs.createClient(options);

        client.on('timeout', (error) => {
            reject(error);
        });

        client.on('connectTimeout', (error) => {
            reject(error);
        });

        client.on('timeLimit', (error) => {
            reject(error);
        });

        client.on('error', (error) => {
            reject(error);
        });

        resolve(client);

    });
}

`

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.