~mna/funweb

2274849cbe5a72e68647d038c0a7a8f883e3005e — Martin Angers 1 year, 7 days ago 51cff7f
start converging towards a functional-friendly middleware signature
3 files changed, 30 insertions(+), 11 deletions(-)

M lib/funweb.js
M lib/logger.js
A lib/mwadapt.js
M lib/funweb.js => lib/funweb.js +12 -9
@@ 6,13 6,14 @@ const compression = require('compression')
const cors = require('cors')
const pug = require('pug')
const logger = require('./logger')
const adapt = require('./mwadapt')

// need some automatic generation of forms/html from code (can be fully controlled with templates or jsx, or auto-generated using a distinct library)
// TODO: make the canonical middleware signature (next, req, res) so it can be curried more easily? Or even (next, [req, res])?

// status and body helper
const handler = (status, body) => R.pipe(
  R.nthArg(1),
  R.last,
  R.invoker(1, 'writeHead')(status),
  R.invoker(1, 'end')(body)
)


@@ 29,6 30,7 @@ const pugHello = pug.compileFile(
  { basedir: tpldir }
)
const helloParams = R.pipe(
  R.head,
  R.prop('url'),
  R.split('/'),
  R.filter(R.pipe(R.isEmpty, R.not)),


@@ 39,20 41,21 @@ const helloParams = R.pipe(
const helloBody = R.pipe(helloParams, pugHello)

// map routes to handlers
const route = (url) => R.pipe(R.prop('url'), R.startsWith(url))
const route = (url) => R.pipe(R.head, R.prop('url'), R.startsWith(url))
const routes = R.cond([
  [route('/hello'), (req, res) => handler(200, helloBody(req))(req, res)],
  [route('/hello'), ([req, res]) => handler(200, helloBody(req))(req, res)],
  [route('/nothello'), handler(200, 'NOT HELLO!')],
  [R.T, serveOrNotFound]
])

/*
// middleware
const logAndNext = (req, res) => logger(req, res, R.thunkify(routes)(req, res))
const compress = compression()
const compressAndNext = (req, res) => compress(req, res, R.thunkify(logAndNext)(req, res))
const compress = adapt(compression())
console.log(compress.length)
// TODO: configure CORS properly for the application's needs
const corsFn = cors()
const corsAndNext = (req, res) => corsFn(req, res, R.thunkify(compressAndNext)(req, res))
const corsFn = adapt(cors())
const app = R.pipe(R.pair, corsFn(compress(logger(routes))))
*/

// start server
const logAddress = R.pipe(


@@ 61,5 64,5 @@ const logAddress = R.pipe(
  R.join(':'),
  (addr) => console.log(`listening on ${addr}...`)
)
const server = http.createServer(corsAndNext)
const server = http.createServer(R.pipe(R.pair, R.curry(logger)(routes)))
server.listen(3000, '127.0.0.1', () => logAddress(server))

M lib/logger.js => lib/logger.js +4 -2
@@ 1,6 1,8 @@
function logger (req, res, next)  {
const R = require('ramda')

function logger (next, [req, res]) {
  const start = Date.now()
  const val = next(req, res)
  const val = next([req, res])
  const end = Date.now()
  // TODO: should take a Writable stream as argument
  console.log(`url=${req.url} status=${res.statusCode} duration=${end - start}ms`)

A lib/mwadapt.js => lib/mwadapt.js +14 -0
@@ 0,0 1,14 @@
const R = require('ramda')

function middleware (fn, next, [req, res]) {
  return fn(req, res, R.thunkify(next)(req, res))
}

// takes a fn that accepts the usual connect middleware arguments
// (req, res, next), where next is nullary, and converts it to the
// (next, [req, res]) signature, as a curried function.
function adapt (fn) {
  return R.curry(middleware)(fn)
}

module.exports = adapt