0.3.0 • Published 5 years ago

@kolcelabs/server.js v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
5 years ago

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
  • response: Array
  • port: number

Basic Structure

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

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