# @marblejs/middleware-body

## Installation

```bash
yarn add @marblejs/middleware-body
```

Requires `@marblejs/core` to be installed.

## Importing

```typescript
import { bodyParser$ } from '@marblejs/middleware-body';
```

## Type declaration <a href="#type-declaration" id="type-declaration"></a>

```haskell
bodyParser$ :: BodyParserOptions -> HttpMiddlewareEffect
```

## Parameters

| parameter | definition                      |
| --------- | ------------------------------- |
| *options* | \<optional> `BodyParserOptions` |

***BodyParserOptions***

| ***parameter*** | definition                      |
| --------------- | ------------------------------- |
| *parser*        | \<optional> `RequestBodyParser` |
| *type*          | \<optional> `Array<string>`     |

The `type` option is used to determine what media type the middleware will parse. It is passed directly to the [type-is](https://www.npmjs.org/package/type-is#readme) library and this can be an extension name (like `json`), a mime type (like `application/json`), or a mime type with a wildcard (like `*/*` or `*/json`). Defaults to `*/*`.

## Basic usage

{% code title="app.ts" %}

```typescript
import { bodyParser$ } from '@marblejs/middleware-body';

export default httpListener({
  middlewares: [bodyParser$()],
  effects: [/* ... */],
});
```

{% endcode %}

Lets assume that we have the following *CURL* command, which triggers `POST /api/login` endpoint:

```bash
$ curl --header "Content-Type: application/json" \
  --request POST \
  --data '{ "username": "foo", "password": "bar" }' \
  http://localhost:3000/api/login
```

Using previously connected `bodyParser$` middleware, the app will intercept the following payload object:

```typescript
req.body = {
  username: 'foo',
  password: 'bar',
};
```

The *POST* request body can be intercepted like follows.

{% code title="login.effect.ts" %}

```typescript
import { r } from '@marblejs/core';

export const login$ = r.pipe(
  r.matchPath('/login'),
  r.matchType('POST'),
  r.useEffect(req$ => req$.pipe(
    map(req => req.body as { username: string, password: string }),
    map(body => ({ body: `Hello, ${body.username}!` }))
  )));
```

{% endcode %}

{% hint style="danger" %}
All properties and values in `req.body` object are untrusted (unknown) and should be validated before trusting.
{% endhint %}

{% hint style="info" %}
This middleware does not handle multipart bodies.
{% endhint %}

## Advanced usage

The middleware does nothing if request *Content-Type* is not matched, which makes a possibility for chaining multiple parsers one after another. For example, we can register multiple middlewares that will parse only a certain set of possible *Content-Type* headers.

**Default parser:**

```typescript
import { bodyParser$ } from '@marblejs/middleware-body';

bodyparser$();
```

Parses *application/json* (to JSON), *application/x-www-form-urlencoded* (to JSON), *application/octet-stream* (to Buffer) and *text/plain* (to string) content types

**JSON parser:**

```typescript
import { bodyParser$, jsonParser } from '@marblejs/middleware-body';

bodyParser$({
  parser: jsonParser,
  type: ['*/json', 'application/vnd.api+json'],
})
```

Parses `req.body` to JSON object.

**URLEncoded parser:**

```typescript
import { bodyParser$, urlEncodedParser } from '@marblejs/middleware-body';

bodyParser$({
  parser: urlEncodedParser,
  type: ['*/x-www-form-urlencoded'],
});
```

Parses encoded URLs `req.body` to JSON object.

**Text parser:**

```typescript
import { bodyParser$, textParser } from '@marblejs/middleware-body';

bodyParser$({
  parser: textParser,
  type: ['text/*'],
});
```

Parses `req.body` to string.

**Raw parser:**

```typescript
import { bodyParser$, rawParser } from '@marblejs/middleware-body';

bodyParser$({
  parser: rawParser,
  type: ['application/octet-stream'],
}),
```

Parses `req.body` to Buffer.

## Custom parsers

If the available parsers are not enough, you can create your own body parsers by conforming to `RequestBodyParser` interface. The example below shows how the `jsonParser` looks underneath.

```typescript
export const jsonParser: RequestBodyParser = req => body =>
  JSON.parse(body.toString());
```
