I/O parser for nodejs http request


Keywords
node-req, req, node-http-request, http-request, http, node-http, request
License
MIT
Install
npm install node-req@2.1.2

Documentation

Facade over req object to consistently read request values.



Node req is a facade to be used by any framework to read the request values. The req object of Node.js HTTP request is very bare bones and it can get cumbersome to consistently read information for a given request.

Table of Contents

Features

  • Handles inconsistencies between different header names like referer and referrer.
  • Proxy headers support from reverse proxies like nginx or apache.
  • Content negotiation using Accept headers.
  • Form method spoofing support.
  • Helper methods.
  • Typings support
  • Extendable from outside
  • Thoroughly tested.

Getting started

Install the package from npm as follows:

npm i node-req

# yarn
yarn add node-req

and then use it by importing it as follows:

const { Request } = require('node-req')
const http = require('http')

http.createServer(function (req, res) {
  const request = new Request(req, res, {})
  res.end(`Url without query string is ${request.url()}`)
})

The url property on Node.js core req object returns the URL with query string and in order to drop query string, you will have to parse the URL manually.

Whereas, with node-req, the request.url() method supports both by passing a parameter to include the query string.

Working with bodyparser

Body parser job is to read the request body (probably from a middleware) and then expose it somehow to the end user. This module offers a handful of methods to consume the bodyparser output and then share it via pre-built methods.

http.createServer(function (req, res) {
  const request = new Request(req, res, {})

  const body = getRequestBodySomeHow(req)
  request.setInitialBody(body)

  console.log(request.all())
})

Along with request.all(), you can use all of the following methods.

request.post()

Get the request body as it is.

request.post()

request.all()

Get merged copy of request body and query string.

request.all()

request.input(key, defaultValue?)

Returns the value for a key from request.all(). The defaultValue is used when original value is undefined or null.

request.except(keys[])

Returns an object of values except the given keys.

request.except(['submit', 'csrf'])

request.only(keys[])

Returns an object of values only for the given keys.

request.only(['username', 'age'])

Updating request data

Everything inside request is not subject to mutations, apart from the request body or query string object.

It is recommended to use inbuilt methods when trying to mutate these values, so that this module can keep a safe copy of original data.

updateBody(body: object)

Mutate the request body

request.updateBody(newBodyObject)

// reflects new body
request.all()

updateQs(data: object)

Mutate query string object

request.updateQs(data)

// reflects new query string
request.all()
request.get()

Why update request body or query string?

Updating request body or query string is the first step you will perform to ensure the user data is consistent and clean before your app can consume it.

Now after the mutation, you do want to keep the copy of original data, so that if their are any errors, you can reflect the original data copy to the end user.

For example:

  1. The form accepts amount of an item in Euros(€).
  2. Your server converts it to cents before validating the form values.
  3. If their are any errors during the validation, you want the form to show the amount back in Euros(€) and not cents.
http.createServer(function (req, res) {
  const request = new Request(req, res, {})

  /**
   * Step 1: Original request body submitted by
   * the user.
   */
  const body = getRequestBodySomeHow(req)
  request.setInitialBody(body)

  /**
   * Step 2: Sanitize data
   */
  const body = request.all()
  body.amount = toCents(body.amount)
  request.updateBody(body)

  /**
   * Step 3: Validate data
   */
  validate(request.all())

  /**
   * Step 4: Assuming validation failed and reflect
   * original data back in form
   */
  res.send({
    original: request.original()
  })
})

Typescript support

The module is written in Typescript, so expect intellisense to work out of the box. Also an interface is exported, which you can extend if extending the original Request class.

import { IRequest: BaseIRequest } from 'node-req/build/src/IRequest'

export interface IRequest extends BaseIRequest {
  myCustomMethod (): string
}

and then use it as follows

import { IRequest } from './my/interfaces'

http.createServer(function (req, res) {
  const request: IRequest = new Request(req, res, {})
  request.myCustomMethod() // intellisense works
})

Extending via Macros

The module extends macroable, which allows extending classes from outside in. You can use the following methods to extend the prototype of the Request class.

import { Request } from 'node-req'

// Added as a method
Request.macro('getTime', function () {
  return new Date().getTime()
})

// Added as property
Request.getter('getTime', function () {
  return new Date().getTime()
})

// Added as singleton property
Request.getter('getTime', function () {
  return new Date().getTime()
}, true)

Later, using the request instance, you can use getters and macros.

http.createServer(function (req, res) {
  const request = new Request(req, res, {})

  request.getTime // getter
  request.getTime() // macro
})

Difference from other frameworks

You don't need this module, if you are using Express or Koa, since their req object is already decorated with handful of convivent getters.

In case you are building a framework or using a framework like micro, then this module can save lots of time.

API

The API docs are generated using Typedoc and can be found here.