neverthrow icon indicating copy to clipboard operation
neverthrow copied to clipboard

Early return / short circuit pattern

Open cjroebuck opened this issue 1 year ago • 2 comments

Hey , any recommendations on how to do the following pattern in a route handler, hopefully the pseudo code makes sense:

(req, res, next) => {
  loadUser(req)
    .andThen(validateUser)
    .andThen(lookupCache) // <-- if lookupCache actually finds a result in the cache, we want to skip straight to the match() and return a response
    .andThen(validateOptions)
    .andThen(doSomethingExpensive)
    .andThen(putInCache)
    .match(result=>{
      res.send(200,{status:"ok",result})
    },err=>{
      res.send(400,{status:"notok",error:err.message});
    })
}

Basically.. I want to short circuit the pipeline if lookupCache finds a result, but continue otherwise.

The only way I can see to do it without breaking this out into two pipelines.. is to return a special error and handle that in the error case..

Otherwise this is kinda what i'm doing now.. but it feels ugly somehow..

(req, res, next) => {
  loadUser(req)
    .andThen(validateUser)
    .andThen(lookupCache)
    .match(result =>{
      if(result.isCacheHit){
        res.send(200,{status:"ok",result});
        return next();
      }      
      validateOptions(result)
        .andThen(doSomethingExpensive)
        .andThen(putInCache)
        .match(result=>{
          res.send(200,{status:"ok",result})
        },err=>{
          res.send(400,{status:"notok",error:err.message});
        })
    },err=>{
      res.send(400,{status:"notok",error:err.message})
    }) 
}

it feels ugly because i'm doing the res.send part in multiple places, when I just want to handle it in one .match call..

cjroebuck avatar May 16 '23 15:05 cjroebuck

Hello @cjroebuck

This is how I proceed

(req, res, next) => {
  loadUser(req)
    .andThen(validateUser)
    .andThen(lookupCache)
    .andThen((cache) => {
      if(cache) return Ok(cache)

      return validateOptions()
        .andThen(doSomethingExpensive)
        .andThen(putInCache)
    })
    .match(result=>{
      res.send(200,{status:"ok",result})
    },err=>{
      res.send(400,{status:"notok",error:err.message});
    })
}

paduc avatar May 16 '23 16:05 paduc

I see.. thank you @paduc, that is a bit nicer!

cjroebuck avatar May 16 '23 16:05 cjroebuck