> For the complete documentation index, see [llms.txt](https://jbreckmckye.gitbook.io/node-ts-architecture/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jbreckmckye.gitbook.io/node-ts-architecture/creating-bindings/what-are-bindings.md).

# What are bindings?

{% hint style="warning" %}
This project and documentation are work in progress
{% endhint %}

{% hint style="info" %}
Example code: [src/bindings](https://github.com/jbreckmckye/node-typescript-architecture/tree/master/src/bindings)
{% endhint %}

Bindings take a library that has been instantiated with adapters, and expose it to the outside world. In the case of the example project, our binding is a REST HTTP interface, but you could write a binding to support GraphQL, pub/sub events, or even commands from a user interface (like in a CLI app).

### Example: the Express binding

To make the community library app into a webservice, I've written an Express.js binding that maps library functions to incoming HTTP calls:

```typescript
import express from 'express'
import bodyParser from 'body-parser'
import { Library, Entities } from '@lib'
import { route } from './route'

export function binding (lib: Library) {
  const port = 3000
  const app = express()

  app.use(bodyParser.json())

  app.get('/health', (req, res) => res.sendStatus(200))

  app.post('/book', route({
    fn: lib.book.add,
    validateInput: Entities.castBookInput,
    onSuccess: (res, result) => res.status(201).json(result)
  }))

  app.post('/loan', route({
    fn: lib.loan.take,
    validateInput: Entities.castLoanInput,
    onSuccess: (res, result) => res.status(201).json(result)
  }))

  app.post('/return/:bookID', route({
    fn: lib.loan.return,
    validateInput: Entities.castUUID,
    getInput: (req, params) => (params as any).bookID,
    onSuccess: (res) => res.sendStatus(200)
  }))

  app.post('/user', route({
    fn: lib.user.add,
    validateInput: Entities.castUserInput,
    onSuccess: (res, result) => res.status(201).json(result)
  }))

  app.delete('/user/:userID', route({
    fn: lib.user.remove,
    validateInput: Entities.castUUID,
    getInput: (req, params) => (params as any).userID,
    onSuccess: (res) => res.sendStatus(200)
  }))

  app.listen(port, () => {
    console.log('Example library app listening at port', port)
  })
}
```

The `Route` function is defined in [src/bindings/express.route.ts](https://github.com/jbreckmckye/node-typescript-architecture/blob/master/src/bindings/express/route.ts) and takes an object with four fields:

* the **fn** from the library to call
* a function that validates the input into the format expected
* a function to extract input from Express' `Request` object
* a function for handling success and responding with the right status code

The example route function also manages validation failure and how to log and respond to exceptions.

{% hint style="info" %}
The route function isn't provided as a cast iron code example, rather a suggestion for how you can reduce boilerplate in your Express apps. Use it just as a starting point and make your own customisations.
{% endhint %}
