npm package: @kolcelabs/server.js
Description: A Proper Node.js Framework for Web Applications 
Author: James Kolce
Latest version: 0.3.0

# Server.js: A Proper Node.js Framework for Web Applications

> TODO: Update this file

Server.js provides a single function to declaratively compose any kind of Node.js web application. Instead of providing extensive functionality, it provides only the starting point to organize a Node.js application without making any assumptions.

```
npm install @kolcelabs/server.js
```

## Features

- **Small**: Only ~1KB.
- **Generic**: Doesn't include any functionality other than the main function to organize the application.
- **Declarative**: Built around the principle of descriptions instead of state-based sequences.
- **Clear Architecture**: All the application logic can be described in terms of intermediary functions for both the *request* and the *response* objects. This concept is equivalent to *middleware* in other frameworks, but conceptually simpler.

## Usage

Server.js aims to be as generic as possible; the only goal is to provide a starting point for any kind of web application without having to deal with unnecessary complications. The package exposes a single function that accepts an object with the descriptions of your application. The only three predefined fields in this description are:

- `request`: *Array<any>*
- `response`: *Array<any>*
- `port`: *number*

### Basic Structure

```typescript
import { server } from '@kolcelabs/server.js'

server({
  port: 3000,

  request: [
    data => { /* Intermediary function */ },
    data => { /* Intermediary function */ }
  ],

  response: [
    data => { /* Intermediary function */ }
    data => { /* Intermediary function */ }
  ],

  /* Any other data you want to include to describe your application */
})
```

### Example

```typescript
import { server } from '@kolcelabs/server.js'

// Example functions, you can use the implementation you want:
import { parseRequest } from '@kolcelabs/request.js'
import { findRoute } from '@kolcelabs/router.js'
import { set } from 'lodash'

server({
  port: 3000,
  resources: {
    '/': {
      'GET': {
        handler: request => ({
          status: 200,
          payload: 'Hello world!'
        })
      }
    }
  },
  request: [
    data => {
      // You have access to a `data.httpRequest` object here containing the raw request from Node.js
      // Also data.server to access your application description (this object)
      return {
        request: parseRequest(data.httpRequest),
        server: data.server
      }
    },
    data => {
      // Each function receives the data returned by the previous one
      // Because of the previous function, in `data` we will have:
      // `request`, `server` and `cookies`.
      // Just to have a more intuitive request object. Now  we can do the routing
      // logic by passing the request path and our routing description (`resources`)
      // to a routing library. This will depend on the actual implementation you
      // decide to use in your application.

      return set(data, 'handler', findRouter(data.request.path, data.server.resources))

      // Using a `set` function simplifies the modification of the data object because you
      // don't need to specify all the fields again. You can use the one provided by
      // lodash or any other implementation you prefer.
    },
    data => {
      // At this point we have a `handler` function that we can apply to our request
      // to get a response. Since this is the last function, we can just return the result of
      // the function, which is the response we are going to send to the client. This value
      // is then passed to the first function in the `response` array below.
      return data.handler(data.request)
    }
  ],
  response: [
    data => {
      // The `data` object contains the value returned by `data.handler(data.request)` in the
      // last intermediary function of the request array.
      // Usually we will prepare the response object before sending it to the client, maybe
      // adding some default headers and turn the payload (content of the response) into a string.
      // The returned value of the last intermediary function in this array is the one being sent
      // to the client. It accepts the following fields: `status`, `payload` and `headers`.

      return {
        status: data.status,
        payload: JSON.stringify(data.payload),
        headers: {
          'Content-Type': 'application/json'
        }
      }
    }
  ]
})

```

## License

MIT — James Kolce