0

So I am working on a side project and I am trying to create my own personal utility library and I am making use of the ES6 class. This is what the class looks like currently.

class HttpUtils {
  throwHttpError({ code, id, title, message, stack }) {
    const toReturn = {
      errors: [
        {
          id,
          title,
          error: message,
          stack,
        },
      ],
    }

    return {
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      code,
      data: JSON.stringify(toReturn),
    }
  }

  wrapAsync(fn) {
    return (req, res) => 
      fn(req, res).catch((error) =>  {
        return this.throwHttpError({
          message: error.message,
          title: error.name,
          stack: error.stack,
          code: error instanceof RequiredParameterError ||
                error instanceof MessageBrokerError ||
                error instanceof SendGridError
              ? 400
              : 500 || error instanceof UnauthorizedError
              ? error.statusCode
              : 401 || error instanceof DatabaseError
              ? error.statusCode
              : 400,
            })
      })
  }
}

The issue I am facing currently is that the wrapAsync method doesn't work the way it is meant to work. This is how I implement the wrapAsync method.

import { HttpUtils } from 'my-utils'

const http = new HttpUtils()

const someRandomFunc = ({ someDependency }) => {
  return http.wrapAsync(async (httpRequest) => {
    const { user } = httpRequest
    const { ...details } = httpRequest.body

    await someDependency({ user, ...details })
    return http.apiResponse({
      status: true,
      message: 'Function completed',
      data: null,
      statusCode: 200
    })
  })
}

export default someRandomFunc

Anytime an error is thrown, I get this in my console.

(node:13444) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client                                      
    at ServerResponse.setHeader (_http_outgoing.js:536:11)                                                                                                              
    at ServerResponse.header (K:\moneyguard\node_modules\express\lib\response.js:771:10)                                                                                
    at ServerResponse.send (K:\moneyguard\node_modules\express\lib\response.js:170:12)                                                                                  
    at K:\moneyguard\api\express\/index.js:33:57                                                                                                                        
    at processTicksAndRejections (internal/process/task_queues.js:93:5)                                                                                                 
(Use `node --trace-warnings ...` to show where the warning was created)                                                                                                 
(node:13444) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either 

I tried to console.log the error that might have been thrown in the API, it is logged correctly and formatted correctly based on throwHttpError, e.g

errors: [
 {
  title: RequiredParameterError,
  error: Name cannot be null,
  stack: ...some stack trace
 }
]

But the wrapAsync method doesn't behave properly, could it be as a result of the this keyword or could I be missing something?

Thanks in advance.

thatguy
  • 370
  • 1
  • 5
  • 22
  • That "this" you are using does not represent the class instance. Create member instance at the class level (the same level where you are delaring the methods you want to reference with a class-level "this" and set the value as this and use thae variable instead. Take a look at https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback for more context. – Mark M Nov 29 '20 at 17:59
  • Thanks, using arrow functions seemed to fix things up a little. But now, there's something I discovered in the ```wrapAsync``` method. I noticed that the ternary operator evaluation is off, e.g ```code: error instanceof InvalidPropertyError ? 400 : 500``` the ternary operator always evaluated to the falsy value even though the error is indeed an instance of the said class. Any idea why this might happen? – thatguy Nov 29 '20 at 20:11
  • Yikes. With that level of nesting of ternary statements I'm not surprised you have issues with that. If I were you I would move the evaluation of the code property into a function and flatten out that logic into a switch or set of if statements. – Mark M Nov 30 '20 at 03:57
  • @MarkM I actually did move the logic to a separate function, but the error thrown is an instance of the Base Error Class, not the Error classes I created personally, Using normal functions, it works but I tried converting this utility function to a Class and everything is acting off. When a ```UnauthorizedError``` is thrown, and I do ```error instanceof UnauthorizedError``` I get false printed to the console, but when I do this ```error instanceof Error``` I get true. The error is meant to be an instanceof the Error class that's thrown, but it's defaulting to the Base Error Class. Any idea why – thatguy Nov 30 '20 at 08:44

0 Answers0