Result: Composition and Error handling
Tags: javascript, typescript, rop, functional
Published: 2019-06-09 13:01:25

---
title: Result: Composition and Error handling
published: true
tags: javascript,typescript,ROP,functional-programming
canonical_url: https://patrickroza.com/blog/result-composition-and-error-handling/
series: Functional Programming - Clean architecture and DDD
cover_image: https://images.ctfassets.net/0ylo3msmt13u/45iAXHssqMk0jN5xtK001H/5c2a312192fb161a4d04bcad29d0ecd1/rop-3cc4d947e7c4e857.jpeg?w=889&h=500&q=50&fm=webp&bg=rgb%3A000000
description: We can improve our error handling and composition by leveraging a Result class and several other tools from the functional programming world.
---

We can improve our error handling and composition by leveraging a Result class and several other tools from the functional programming world.

Instead of throwing errors, we wrap our results. Either the Result is an Error value, or a Success value, in the process documenting the possible errors. Callers must first examine and unwrap the Result, handling either the Success or Failure case. Paving the way for more functional programming and composition.

For a more complete introduction to the Result class and Railway Oriented Programming:

- [https://fsharpforfunandprofit.com/rop/](https://fsharpforfunandprofit.com/rop/)
- [https://dev.to/\_gdelgado/type-safe-error-handling-in-typescript-1p4n](https://dev.to/_gdelgado/type-safe-error-handling-in-typescript-1p4n)
- [https://khalilstemmler.com/articles/enterprise-typescript-nodejs/handling-errors-result-class/](https://khalilstemmler.com/articles/enterprise-typescript-nodejs/handling-errors-result-class/)

_For implementations check [GitHub #railway-oriented-programming](https://github.com/topics/railway-oriented-programming); ROP in many programming languages (**Python/Go/Java/C#/F#** etc)_

In these series I will share my findings during my (exciting) journey.

## Imperative sample

```javascript
const r = doSomeAction() // Result<string, SomeVariableIsInvalid | ServiceUnavailableError>
if (r.isErr()) { // r: Error<SomeVariableIsInvalid | ServiceUnavailableError>
  if (r.error instanceof SomeVariableIsInvalid) {
    ctx.body = r.error.message
    ctx.statusCode = 400
  } else {
    ctx.statusCode = 500
  }
  return
}
// r: Ok<string>
ctx.body = r.value
ctx.statusCode = 200
```

`doSomeAction` could be implemented like:

```javascript
function doSomeAction(): Result<string, SomeVariableIsInvalid | ServiceUnavailableError> {
  if (!someVariableIsValid) {
    return err(new SomeVariableIsInvalid("some variable is not valid")
  }
  if (!isServiceAvailable()) {
    return err(new ServiceUnavailableError("The service is currently unavailable")
  }

  return ok("success response")
}
```

## Functional sample

```javascript
doSomeAction() // Result<string, SomeVariableIsInvalid | ServiceUnavailableError>
  .map(value => {
    ctx.body = value
    ctx.statusCode = 200
  })
  .mapErr(error => {
    if (error instanceof SomeVariableIsInvalid) {
      ctx.body = error.message
      ctx.statusCode = 400
    } else {
      ctx.statusCode = 500
    }
  })
```

All "operators" must live on the Result object and thus extension is harder. (This is similar to how for instance RxJS started)

## Functional Composition

```javascript
doSomeAction() // Result<string, SomeVariableIsInvalid | ServiceUnavailableError>
  .pipe(
    map(value => {
      ctx.body = value
      ctx.statusCode = 200
    }),
    mapErr(error => {
      if (error instanceof SomeVariableIsInvalid) {
        ctx.body = error.message
        ctx.statusCode = 400
      } else {
        ctx.statusCode = 500
      }
    })
  )
```

The operators are now just functions, easy to extend and roll our own ;-) ([RxJS v5.5](https://blog.hackages.io/rxjs-5-5-piping-all-the-things-9d469d1b3f44) users may see some similarities here)

## Data last

```javascript
const pipeline = pipe(
  map(value => {
    ctx.body = value
    ctx.statusCode = 200
  }),
  mapErr(error => {
    if (error instanceof SomeVariableIsInvalid) {
      ctx.body = error.message
      ctx.statusCode = 400
    } else {
      ctx.statusCode = 500
    }
  })
)

pipeline(doSomeAction())
```

So `pipeline` is now reusable. If only [tc39 proposal-pipeline-operator](https://github.com/tc39/proposal-pipeline-operator) would land soon, so that we get syntactic sugar that will hide some boiler plate and syntactic noise :)

## Building on top

Further decomposition into separate functions, so that they become re-usable, or to separate the levels of abstraction so that the pipeline becomes easier to read.

```javascript
const writeSuccessResponse = value => {
  ctx.body = value
  ctx.statusCode = 200
}

const writeErrorResponse = error => {
  if (error instanceof SomeVariableIsInvalid) {
    ctx.body = error.message
    ctx.statusCode = 400
  } else {
    ctx.statusCode = 500
  }
}

const pipeline = pipe(
  map(writeSuccessResponse),
  mapErr(writeErrorResponse)
)
```

Further decomposition:

```javascript
const writeSuccessResponse = value => {
  ctx.body = value
  ctx.statusCode = 200
}

const writeDefaultErrorResponse = error => {
  ctx.statusCode = 500
}

const writeSomeVariableIsInvalidErrorResponse = error => {
  if (error instanceof SomeVariableIsInvalid) {
    ctx.body = error.message
    ctx.statusCode = 400
  }
}

const pipeline = pipe(
  map(writeSuccessResponse),
  mapErr(writeDefaultErrorResponse),
  mapErr(writeSomeVariableIsInvalidErrorResponse),
)
```

Perhaps another option:

```javascript
const mapErrIf = (errorHandler: error => void, predicate: error => boolean) => 
  error => {
    if (!predicate(error)) { return }
    errorHandler(error)
  }
}
// usage
mapErrIf(_ => ctx.statusCode = 400, error => error instanceOf SomeVariableIsInvalid)
```

And there are of course many other options and forms of composition, let that be the reader's excercise ;-)

## Framework and Sample code

I'm working on an application framework while exploring these topics, that leverages the pipeline composition extensively, Sample app included!

Source code:

- [fp-app framework](https://github.com/patroza/fp-app-framework)
  - [sample app](https://github.com/patroza/fp-app-framework/tree/master/samples/basic)
  - [neverthrow pipe extensions](https://github.com/patroza/fp-app-framework/tree/master/packages/neverthrow-extensions)
  - Uses [neverthrow fork](https://github.com/patroza/neverthrow) (forked from [gDelgado14/neverthrow](https://github.com/gDelgado14/neverthrow))

## What's Next

Next in the series, I plan to introduce the more advanced concepts like `flatMap`, `toTup`, `tee` and others :)

## Further reading

Be sure to also check out [gcanti/fp-ts](https://github.com/gcanti/fp-ts); a heavily functional programming oriented library, especially v2 is looking very promising due to similar pipe composition!